[JS] Promise, async/await

세나정·2023년 6월 5일
0
post-thumbnail

Promise

콜백을 쓰면 지저분한 콜백 헬이
콜백 헬이라고 불리는 지저분한 자바스크립트 코드의 해결책

프로미스 : 내용이 실행은 되었지만 결과를 아직 반환하지 않은 객체
(실행 됐는데 결과값을 나중에 씀)

Then을 붙이면 결과를 반환

Resolve -> then으로 연결
Reject -> catch로 연결
Finally 부분은 무조건 실행

Async/await

(에이씽크, 어웨잇)

위 코드를 아래로 변경 가능

변수에 프로미스가 result된 값이 변수에 저장
당연하게도 await을 쓸 때는 async가 필요함

에러 처리는 try, catch로 처리 만약 try...catch가 없는데 에러가 발생하면 프로미스가 거부 상태로 됨

function 앞에 async키워드를 붙이면 해당 함수는 항상 Promise를 반환, Promise가 아닌 값을 반환하더라도 이행 상태 (fulfilled)의 promise로 값을 감싸 이행된 Promise가 반환


콜백은 비동기가 아니고 비동기 콜백이 비동기, 콜백은 동기일 수도 있고 비동기일 수도 있음

예를 들어, 다음과 같은 콜백함수에선 동기 콜백으로 비동기가 하나도 쓰이지 않음

비동기 콜백의 대표는 setTimeout

다음과 같은 코드는 1초 뒤에 callback이라는 함수의 값을 받고 싶지 않아도 강제로 받아야만 하지만

이렇게 promise로 작성을 해놓을시 promise에 결과값을 저장한 후 나중에 꺼내서 쓸 수 있다는 것

async, await도 프로미스이기 때문에 promise의 then, catch, finally들과 함께 써야함

Promise와 callback

가장 큰 장점은 이렇게 서버와 통신을 할 떄 모아뒀다가 한번에 처리를 할 수 있다는 것

만약 프로미스를 사용하지 않고 callback을 계속 사용한다면 다음과 같이 돼버림

콜백헬의 단점은 보기 안 좋아서도 있지만, 결과값을 바로 받아야만 하는 것이 큰 문제

Promise.all과 Promise.allSettled

Promise.all의 가장 큰 단점, p1~p6 데이터들에서 한 개라도 들어오지 않았다면 바로 catch((error) => 로 빠지게 됨

여기서 문제는 catch는 뭐가 실패했는지 알려주지 않음
그래서 성공한 것들까지 다시 취소 후 재시도를 해봐야함

그것을 보완하기 위해 나온 것이 allSettled

allSettled는 results에 성공 여부를 각각 저장해놓다가 실패한 것들만 필터링해서 다시 시도할 수 있음

그니까 all 말고 allSettled를 씁시다.

*catch는 promise.all([p1, p2, p3, p4, p5])에 대한 catch가 아니라
then( (results) => {} ) 까지 해서에 대한 catch


한 번 비동기는 영원한 비동기

비동기는 동시의 문제가 아닌 "순서의 문제"

동시에 여러가지 일들이 실행되는 것이 아님
비동기 코드는 적혀진 코드와 실제 실행순서가 다른 것

비동기를 동기로 바꿀 생각을 하지마라


콜백이라고 무조건 비동기가 아닌 것을 꼭 이해

비동기의 분석법

비동기를 분석할 땐 다음처럼
백그라운드와 매크로 큐, 마이크로 큐를 추가해서 생각하면 된다.
여기서 백그라운드는, 원래 자바스크립트의 엔진 부분이라고 생각하면 됨
(실제로 존재하는 개념은 아님, 비동기 코드들이 동시에 돌아갈 수 있는 공간이라고 생각)

자바스크립트는 원래부터 싱글스레드이기 때문에 동시라는 개념이 존재하지 않음
하지만 백그라운드에 들어가는 애들은 동시라는 개념이 생김

그래서 다음처럼, 이벤트 루프가 돌면서 태스크큐 (매크로 큐)에 작업들을 쌓고 그 작업들이 앞에서 부터 (FIFO) 나와 콜스택 (CS)에 쌓이는 것 그러다가 콜스택이 비어있으면 2가 들어가는 방식

마이크로 큐(m)에는 promise, process.nextTick이 들어 가고 그 외 나머지 것들은 매크로 큐 (M)에 들어감

백그라운드는 onClick같이 클릭이 됐을 때 그 함수를 매크로 큐에 넣어주는 방식

프로미스라면 promise가 resolve 됐을 때 마이크로 큐에 들어가는 것

만약 마이크로와 매크로 큐에 동시에 들어갔다면 마이크로 큐에 있는 내용이 먼저 들어감

그렇기 때문에 마이크로 태스크큐가 꽉 차있으면 매크로 태스크는 영원히 실행되지 않음

그래서 다음의 결과는 "p a b c"가 됨

그럼 다음과 같으면 어떻게 돼요?

이런 경우엔 예상한대로 적어놓은 순대로 매크로 큐에 쌓임

근데 그냥 비동기 일 땐 순서가 헷갈릴만한 일을 안 하면 됨

한비영비 예시

let a = 2;
setTimeout( () => {
	a = 5;
    console.log(a)
}, 0)

console.log(a) // 2

한번 setTimeout에 들어간 애는 앞으로 쭉 setTimeout에서만 변수값을 바꾸거나 쓰거나 할 수 있음 바깥까지 영향을 미칠 수 없음

profile
압도적인 인풋을 넣는다면 불가능한 것은 없다. 🔥

0개의 댓글