기억 휘발 방지소

자바스크립트의 async/await의 동작 이해하기 본문

Web/JavaScript

자바스크립트의 async/await의 동작 이해하기

choice91 2022. 7. 21. 23:09
728x90
반응형

async/await는 ES8에 등장한 것으로 Promise와 then보다 깔끔하게 코드를 작성할 수 있게 해준다.

 

👉 Promise 방식

function promise() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('success');
    }, 2000);
  });
}

promise()
  .then((result) => {
    console.log(result);
  })
  .catch((e) => {
    console.error(e);
  });

 

👉 async/await 방식

function fn() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('success');
    }, 2000);
  });
}

async function asyncFn() {
  try {
    const result = await promise();
    console.log(result);
  } catch (e) {
    console.error(e);
  }
}

asyncFn();

 

👉 Promise와 async/await 비교

  • Promise에서는 catch로 에러 핸들링이 가능하지만 async/await에서는 에러 핸들링을 할 수 있는 기능이 없어서 try~catch문으로 에러 핸들링을 해야한다.
  • 코드가 길어지면 길어질수록 async/await를 활용한 코드가 가독성이 좋다.
  • async/await를 활용하면 비동기 코드를 동기 코드처럼 읽히게 해준다. ➡️ 코드 흐름을 이해하기 쉽다.

 

👉 async/await 동작 방식

await 키워드를 만나면 다음과 같이 동작한다.

  1. await 키워드가 붙은 대상이 함수라면 해당 함수를 실행
  2. 함수가 아니거나 함수의 실행이 끝나면 async 함수를 잠시 일시정지하고 콜 스택에서 마이크로 태스트 큐로 이동하며 이때, await의 위치를 기억
  3. 해당 함수가 콜 스택에서 나왔으니 나머지 콜 스택에 있는 함수들이 실행된다.
  4. 콜 스택이 모두 비워지면 이벤트 루프는 마이크로 태스트 큐에 있는 await를 만나 옮겨졌던 async 함수들을 콜 스택으로 이동시키고
  5. 해당 함수가 await 됐던 시점부터 다시 실행
const a = () => {
  console.log("a 시작");
  b();
  console.log("a 끝");
};

const b = async () => {
  console.log("b 시작");
  await c();
  console.log("b 끝");
};

const c = async () => {
  console.log("c 시작");
  await d();
  console.log("c 끝");
};

const d = () => {
  console.log("d")
};

a();

위에 코드에 대한 실행결과는 다음과 같다.

a 시작
b 시작
c 시작
d
a 끝
c 끝
b 끝

 

👉 동작 순서

1. a 함수가 호출/실행되어 'a 시작' 출력

Call Stack: [a]
Microtask Queue: []

콘솔 출력 결과
a 시작

 

2. a 함수 안에 있는 b 함수를 호출/실행되어 'b 시작' 출력

Call Stack: [a b]
Microtask Queue: []

콘솔 출력 결과
a 시작
b 시작

 

3. b 함수 내에서 await c(); 를 만났지만 c 함수를 호출/실행하고 콜 스택에 쌓이고 'c 시작' 출력

Call Stack: [a b c]
Microtask Queue: []

콘솔 출력 결과
a 시작
b 시작
c 시작

 

4. c 함수 내에서 await d();를 만났으나 d 함수를 호출/실행하고 콜 스택에 d 추가

Call Stack: [a b c d]
Microtask Queue: []

콘솔 출력 결과
a 시작
b 시작
c 시작

 

5. d 함수가 실행 후 종료되어 콜 스택에서 제거

Call Stack: [a b c]
Microtask Queue: []

콘솔 출력 결과
a 시작
b 시작
c 시작
d

 

6. await d()를 만나 일시정지된 c 함수가 콜 스택에서 마이크로 태스트 큐로 옮겨간다.

Call Stack: [a b]
Microtask Queue: [c]

콘솔 출력 결과
a 시작
b 시작
c 시작
d

 

7. await c()를 만나 일시정지된 b 함수가 콜 스택에서 마이크로 태스크 큐로 옮겨간다.

Call Stack: [a]
Microtask Queue: [c b]

콘솔 출력 결과
a 시작
b 시작
c 시작
d

 

8. 콜 스택에서 하나 남은 a 함수가 실행되어 'a 끝'이 콘솔에 출력되고 a 함수는 콜 스택에서 빠져나간다.

Call Stack: []
Microtask Queue: [c b]

콘솔 출력 결과
a 시작
b 시작
c 시작
d
a 끝

 

9. 콜 스택이 비었으므로 마이크로 태스트 큐에 있는 c 함수가 콜 스택으로 이동하고 await 를 만난 이후부터 실행되어 'c 끝'이 콘솔에 출력되고 콜 스택에서 제거된다.

Call Stack: []
Microtask Queue: [b]

콘솔 출력 결과
a 시작
b 시작
c 시작
d
a 끝
c 끝

 

10. 9번과 마찬가지로  콜 스택이 비었으므로 마이크로 태스크 큐에 있는 b 함수가 콜 스택으로 이동하고 await를 만난 이후부터 실행되어 'b 끝'이 콘솔에 출력되고 콜 스택에서 제거된다.

Call Stack: []
Microtask Queue: []

콘솔 출력 결과
a 시작
b 시작
c 시작
d
a 끝
c 끝
b 끝

 

 

async/await가 비동기 코드지만 동기처럼 보이는 이유도 await를 만난 함수를 마이크로 태스트 큐에 옮겨놓고 콜 스택이 비워졌을 때 실행하기 때문이다.

때문에 await를 만난 이후의 로직에서 await에 대한 결과값을 받을 수 있는 것이다.

 

 

혹시라도 잘못된 정보가 있다면 댓글로 알려주시면 감사하겠습니다!

 

참고
https://velog.io/@jjunyjjuny/JavaScript-asyncawait%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%A0%EA%B9%8C

 

끝!

728x90
반응형

'Web > JavaScript' 카테고리의 다른 글

[JavaScript] shift()와 pop()  (0) 2021.10.05
[JavaScript] sort()  (0) 2021.10.02
[JavaScript] includes()  (0) 2021.09.25
[JavaScript] find()  (0) 2021.09.24
[JavaScript] reduce()  (0) 2021.09.11