HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🐣
프론트엔드 데브코스 3기 교육생
/
📚
3기 스터디 가이드
/
🧑‍💻
CS 학습 및 면접대비 스터디
/
✨
비동기 동작과정 + 제너레이터
✨

비동기 동작과정 + 제너레이터

URL
발표자
수화
과목
Javascript

콜스택은 실행컨텍스트 단위로 쌓임 ⇒ call stack === execution stack

Сall Stack and Execution Stack are different names for the same thing. It is a LIFO stack that is used to store execution contexts created during code execution.
 
 

js는 싱글스레드

  • 싱글스레드 === 스레드 1개
    • 이미지 출처: https://logiwa.tech/how-does-event-loop-works-in-javascript-4205ec04bed
      이미지 출처: https://logiwa.tech/how-does-event-loop-works-in-javascript-4205ec04bed
 

싱글스레드의 장/단점

  • 장점 : 동시성 문제로부터 자유롭다
    • 자세한 건 여기 포스팅 참고
  • 단점 : 한번에 1개의 작업만 가능하다
✨
오래걸리는 비동기 같은 작업들은 어떻게 처리하지?
 

비동기 동작과정 (브라우저 환경기준)

이미지출처: https://felixgerschau.com/javascript-event-loop-call-stack/
이미지출처: https://felixgerschau.com/javascript-event-loop-call-stack/
Note how most of the things in the graphic aren't part of the JavaScript language itself.
Web APIs, the callback queue, and the event loop are all features that the browser provides.
 

시각화 자료

JS Visualizer 9000
JS Visualizer 9000
https://www.jsv9000.app/
notion image
  • 이벤트 루프가 task queue에 있는 task를 들어온 순서대로 처리함
    • 우선순위: microtask queue → macrotask queue
    • microtask
      • promise 관련
    • macrotask
      • script 로드 <script src=”..”>
      • 이벤트핸들러
      • setTimeout 등
📌
엄청 큰 promise task를 수행할 때, 이벤트핸들러가 호출되더라도 promise task끝나고 나서야 작동하겠죠? → 이런 task는 setTimeout 같은거로 작게 쪼개서 수행해 해결하는 방법도 있다고 합니다
 

자바스크립트 엔진이 await를 만나면 어떻게 될까요? @참고

function a() { console.log("a 시작") setTimeout(() => { console.log("a"); }, 1000) console.log("a 끝") } async function b() { console.log('b1') await a() console.log('b2') } // 선언부 b() console.log('c')
정답
b1 a 시작 a 끝 c b2 a
과정
  • 콜스택에 b함수가 쌓이고, 콘솔에 b1이 찍힌다.
  • await 뒤에 있는 a 함수가 콜스택에 쌓이고, 실행한다.
  • 콘솔에 a 시작이 찍히고, setTimeout은 webAPI로 넘어가고, 콘솔에 a 끝이 찍히고, a함수가 콜스택에서 제거된다.
  • b 함수 내의 await를 만나게 돼, b 함수가 일시정지되며, 콜스택을 빠져나와 마이크로 태스크큐로 이동한다.
  • 콘솔에 c가 찍힌다.
  • 콜스택에 비었기에, 이벤트루프에 의해 b함수를 콜스택으로 옮기고, 실행된다.
  • b함수가 일시정지된 await 이후부터 실행되며, 콘솔에 b2가 찍히고, 콜스택에서 제거된다.
  • 콜스택이 비었기에, 이벤트루프에 의해 setTimeout의 콜백함수가 실행돼, 콘솔에 a가 찍히고, 콜스택에서 제거된다.
 

정리

  • 자바스크립트 엔진이 await를 만나면, await를 포함한 함수만 일시정지한다.
  • 비동기 작업은 모두 큐에 저장된 뒤, 콜스택이 비면 이벤트루프에 의해 실행된다.
    • 브라우저 환경에서 이벤트 루프는 1개!
    • 그렇기때문에 비동기라고 다 async await를 사용하기 보단, 꼭 필요한 곳에서만 쓰자 !
      • 안써도 되는 곳은 이 영상에서 자세히 설명해줌 (promise를 받아서 promise를 리턴하는 경우 등)
 
 
📌
async/await는 ES8에 나온 개념, 그 전에는 어떻게 처리할까? - 콜백 - promise.then - generator + promise
 

generator

// 기본문법 // - function* 로 정의 // - next(): 가장 가까운 yield문까지 실행 & yield문의 Value 리턴 // - 중요한 건, 함수가 바로 호출되는 게 아니라 next로 호출됨 function* generateSequence() { yield 1; yield 2; return 3; } let generator = generateSequence(); // 호출 x, 제너레이터 객체 반환 let one = generator.next(); alert(JSON.stringify(one)); // {value: 1, done: false} alert(generator.next().value); // 2 // 양방향 소통가능 function* getUsername() { let username = yield "너의 이름은?"; alert(username); } let generator = getUsername(); alert(generator.next().value); // "너의 이름은?" generator.next("수화");
 
 

generator 비동기처리

generator + promise를 이용해, 비동기처리를 동기식 코드처럼 작성하는 패턴이 있었음
  • 아래 코드는 babel을 이용해 ES7로 트랜스파일링한 코드
  • 실제 사례 비동기 코드
// ES8(async,await) 지원 function a() { console.log('a') } async function b() { console.log('b1') await a() console.log('b2') } b() console.log('c')
// async,await 지원 x "use strict"; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function a() { console.log("a"); } function b() { return _b.apply(this, arguments); } function _b() { _b = _asyncToGenerator(function* () { console.log("b1"); yield a(); console.log("b2"); }); return _b.apply(this, arguments); } b(); console.log("c");
 

그래서, generator 배워서 어디에 씀?

  • async ~ await 못쓰는 구형 브라우저 지원할 때, babel 변환 시, 제너레이터 코드 읽기
  • redux-saga
  • 등등
 
 

읽어보면 좋을 자료

이벤트 루프와 매크로태스크, 마이크로태스크
브라우저 측 자바스크립트 실행 흐름은 Node.js와 마찬가지로 이벤트 루프 에 기반합니다. 따라서 이벤트 루프가 어떻게 동작하는지 잘 이해하고 있어야 최적화나 올바른 아키텍처 설계가 가능해집니다. 이번 챕터에선 이벤트 루프가 어떻게 동작하는지에 대한 이론과 함께, 이를 어떻게 실무에 적용할 수 있는지에 대해서 알아보겠습니다. 이벤트 루프(event loop) 정의는 아주 간단합니다.
이벤트 루프와 매크로태스크, 마이크로태스크
https://ko.javascript.info/event-loop
이벤트 루프와 매크로태스크, 마이크로태스크
이벤트 루프와 워커 풀을 막지 마세요! | Node.js
만약 당신이 간단한 스크립트보다 더 복잡한 코드를 작성하길 원하신다면, 해당 문서를 읽는 것은 당신의 애플리케이션의 성능을 더 좋게, 보안을 안전하게 하는데 도움을 줄 것입니다. 해당 문서는 Node.js 서버를 기준으로 작성되었지만, 기본적인 개념은 복잡한 Node.js 애플리케이션에서도 적용됩니다. OS마다 세부 내용은 달라질 수 있으며 해당 문서는 리눅스를 기준으로 작성되었습니다.
이벤트 루프와 워커 풀을 막지 마세요! | Node.js
https://nodejs.org/ko/docs/guides/dont-block-the-event-loop/
이벤트 루프와 워커 풀을 막지 마세요! | Node.js
Faster async functions and promises
Faster and easier-to-debug async functions and promises are coming to V8 v7.2 / Chrome 72.
Faster async functions and promises
https://v8.dev/blog/fast-async
 

참고자료

  • 비동기 동작과정
    • JavaScript Event Loop And Call Stack Explained | Felix Gerschau
      My goal with this article is to teach you how JavaScript works in the browser. Even though I've been working with JavaScript my whole career, I didn't get how these things work until recently. I still forget how this works from time to time. That's why I wrote this article.
      JavaScript Event Loop And Call Stack Explained | Felix Gerschau
      https://felixgerschau.com/javascript-event-loop-call-stack/
      JavaScript Event Loop And Call Stack Explained | Felix Gerschau
      마이크로태스크
      프라미스 핸들러 .then/catch/finally 는 항상 비동기적으로 실행됩니다. 프라미스가 즉시 이행되더라도 .then/catch/finally 아래 에 있는 코드는 이 핸들러들이 실행되기 전에 실행됩니다. 예시: 예시를 실행하면 '코드 종료'가 먼저, '프라미스 성공!'이 나중에 출력되는 것을 볼 수 있습니다. 프라미스는 즉시 이행상태가 되었는데도 말이죠. 뭔가 이상하네요. 왜 .then 이 나중에 트리거 되었을까요? 그 이유에 대해 알아봅시다.
      마이크로태스크
      https://ko.javascript.info/microtask-queue
      마이크로태스크
  • 제너레이터
    • 제너레이터
      일반 함수는 하나의 값(혹은 0개의 값)만을 반환합니다. 하지만 제너레이터(generator)를 사용하면 여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있습니다. 제너레이터와 이터러블 객체 를 함께 사용하면 손쉽게 데이터 스트림을 만들 수 있습니다. 제너레이터를 만들려면 '제너레이터 함수'라 불리는 특별한 문법 구조, function* 이 필요합니다. 예시: 제너레이터 함수는 일반 함수와 동작 방식이 다릅니다.
      제너레이터
      https://ko.javascript.info/generators
      제너레이터
      async await 동작원리
      async 와 await는 어떻게 동작할까? 내부에서 어떤 식으로 동작하는지를 파악하기 위해서 babel의 try it out 에서 트랜스파일링을 해보고 파악해보자. 아래 코드를 갖고 테스트할 예정이고 비동기 함수는 사용하지 않았다. async, await는 비동기함수만 사용하는거 아니야? 라고 생각할 수 있지만 그렇지 않다. 어떤 함수에도 await을 적용할 수 있다. 먼저 아래의 코드의 결과값을 예상해보자.
      async await 동작원리
      https://velog.io/@proshy/async-await-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC#ref
      async await 동작원리
      [10분 테코톡] 빅터의 Generator와 Async/Await
      🙋‍♀️ 우아한테크코스의 크루들이 진행하는 10분 테크토크입니다. 🙋‍♂️ '10분 테코톡'이란 우아한테크코스 과정을 진행하며 크루(수강생)들이 동료들과 학습한 내용을 공유하고 이야기하는 시간입니다. 서로가 성장하기 위해 지식을 나누고 대화하며 생각해보는 시간으로 자기 주도적인 성장을 지향하는 우아한테크코스의 문화 중 하나입니다. 🌕우아한테크코스란 🌕 우아한테크코스는 일반 사용자용 서비스를 개발하는 회사가 필요로 하는 역량을 가진 프로그래머를 양성하기 위한 교육입니다.
      [10분 테코톡] 빅터의 Generator와 Async/Await
      https://www.youtube.com/watch?v=ZrdHtL1gcEI&list=LL&index=6&t=1s&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC
      [10분 테코톡] 빅터의 Generator와 Async/Await
      async/await native implementations
      How exactly does async/await work in existing native implementations? If we look at the actual native implementation of async await in v8 we can clearly see both promise and generator as the obvious basis of async-await implementation, also in the parser it clearly states the generator-promise nature of desugaring async-await.
      async/await native implementations
      https://stackoverflow.com/questions/46908575/async-await-native-implementations
      async/await native implementations