콜스택은 실행컨텍스트 단위로 쌓임 ⇒ 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개
싱글스레드의 장/단점
- 장점 : 동시성 문제로부터 자유롭다
- 자세한 건 여기 포스팅 참고
- 단점 : 한번에 1개의 작업만 가능하다
오래걸리는 비동기 같은 작업들은 어떻게 처리하지?
비동기 동작과정 (브라우저 환경기준)
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.
시각화 자료

- 이벤트 루프가 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
- 등등
읽어보면 좋을 자료
참고자료
- 비동기 동작과정
- 제너레이터