2021.04.11 데일리 회고

천영석·2021년 4월 11일
0

Facts

  • 하브루타 스터디에 참여해서 공부를 했다.(8시간)

Feelings & Findings

하브루타 스터디에 참여해서 공부를 했다.

주제는 비동기였다. async await, generator, task queue/microtask queue/animation frames, Promise 등 여러 가지 주제에 관해 토론을 했다.

사실 오늘은 하브루타 후에 css와 피드백을 보면서 공부할 예정이었다. 하지만 다른 것을 하나도 하지 못하고 하브루타 때 나왔던 주제인 async await, Promise, generator에만 몰입했다. 한 크루에게서 나온 의문점에서 시작되었다.

async function wait() {
  await new Promise((resolve, reject) => setTimeout(resolve, 1000));
  return 'yay';
}

function foo1() {
  wait();
  return Promise.resolve('yay');
}

function foo3() {
  const result = wait();
  return result;
}

(async () => {
  console.log('foo1', await foo1()); // 즉시 -> console.log
  console.log('foo3', await foo3()); // 1s delay -> console.log
})();

console.log('aa');

// aa
// foo1 yay
// 1초 후 foo3 yay

여기에서 왜 foo3은 return을 할 때 1초를 기다리는지에 대한 궁금증이었다. 지금 생각해보면 당연히 async await으로 실행했기 때문에 foo3의 결과인 Promise를 기다려서 1초 후에 결과가 나오는 것이지만, 공부를 하기 전엔 이것을 알지 못했다. 심지어는 return이 1초를 기다렸다가 result를 return하는 것인 줄 알았다.

결론은 무엇일까? await은 내부적으로 제너레이터 함수를 만들어서 yield로 바뀌게 된다. 그 후에 async에서는 제너레이터 실행기를 작동시켜 next 메서드를 실행시킨다. 그 뒤에 next 메서드의 실행 결과 값에서 done: false가 나오면 result.value.then((res) => 재귀함수(res))를 실행시킨다.
간단히 말해서 next 메서드를 실행시켜서 done: true가 나올 때까지 then으로 Promise의 resolve 값을 받아서 실행하는 것이다.

다시 돌아와서 await foo1()은 foo1을 next 메서드로 실행시키고, foo1의 결과 값인 value: Promise를 then으로 실행시킨다. then으로 넘어갔으니 microtask queue로 옮겨지게 되고, 콜 스택이 비워졌으니 aa를 실행하는 것이다. 이제 then의 결과로 yay가 나오게 되면 다음 await foo3()을 실행하는 것이다.
여기에서도 마찬가지로 foo3을 next 메서드로 실행시키고, foo3의 결과 값인 value: Promise를 then으로 실행시킨다. 그 후에 microtask queue로 옮겨지고, 1초 후에 값을 받아서 console.log에 foo3 yay가 찍히게 된다.

결국 처음 await foo1()도 곧바로 실행되는 것 같지만 then으로 한 번 넘어가기 때문에 비동기로 작동한다. 그래서 밑에 있는 aa가 먼저 실행되는 것이다.

여기까지 깨닫는 데 너무나 오랜 시간이 걸렸다. 약 6시간은 걸린 것 같다. 그래서 오늘은 별 소득이 없다고 생각했는데, 블로그에 글을 쓰면서 술술 써지는 것을 보니 그렇게 소득이 없지는 않은 것 같다. 완벽하게 위와 같은 방식으로 동작하는지에 대한 확신은 없다. 뇌피셜이다.
하지만 확실한 것은 async 함수에 await이 할당되었을 때부터 비동기로 동작한다는 것이다.

(async () => {
  console.log('foo1', foo1()); 
  console.log('foo1', foo1()); 
  console.log('foo1', foo1()); 
  console.log('foo1', await foo1()); 
  console.log('foo1', await foo1()); 
  console.log('foo1', await foo1()); 
})();

console.log('aa');
// foo1 Promise {<fulfilled>: "yay"}
// foo1 Promise {<fulfilled>: "yay"}
// foo1 Promise {<fulfilled>: "yay"}
// aa
// foo1 yay
// foo1 yay
// foo1 yay

이렇게 동작한다.

비동기에 관해 많은 공부를 할 수 있었고, async await이 동작하는 원리에 대해 어렴풋이 알게 된 하루였다. 바벨로 async await을 es6로 변환시켜보기도 하면서 여러 가지 시도를 많이 해봤고, generator와 Promise도 같이 공부가 된 것 같다.

Plans

  • 준며들다 준비
  • css 스터디 준비
profile
느려도 꾸준히 발전하려고 노력하는 사람입니다.

0개의 댓글