티스토리 뷰
#js #js기본
JavaScript는 단일 스레드 언어다.
한 번에 하나의 작업만 처리할 수 있다.
이러한 특성 때문에 비동기 처리 모델을 사용하여 I/O 작업 등이 진행되는 동안 다른 작업을 수행할 수 있도록 한다.
비동기 콜백 함수는 일반적으로 두 가지 종류의 큐에서 관리된다.
우선순위: micro task queue > task queue
1. 마이크로 태스크 큐 (micro task queue)
Promise의 then 메서드나 async/await 등에 의해 생성된 콜백 함수가 저장되는 곳입니다.
이벤트 루프가 각 반복에서 호출 스택을 비우면, 마이크로 태스크 큐 를 확인하고 그 안의 모든 콜백을 실행합니다.
2. 태스크 큐 (task queue)
setTimeout, setInterval 과 같은 API에 의해 생성된 콜백 함수가 저장되는 곳이다.
이벤트 루프가 각 반복에서 호출 스택 과 마이크로 태스크 큐 를 비운 후에야 확인하고 실행한다.
코드 예시 1
function aaa() {
setTimeout(() => {
console.log('d');
}, 0);
console.log('c');
}
setTimeout(() => {
console.log('a');
aaa();
}, 0);
Promise.resolve().then(() => { // ✨ then의 콜백은 resolve가 된 후 실행된다.
aaa(); // (1)
console.log('b');
});
- 일단,
function aaa,setTimeout,Promise.resolve.then()모두 메인 스크립트에서 동기적으로 호출 - setTimeout이 태스크큐에 등록 (ㄱ)
- Promise.resolve().then의 콜백이나 async/await의 콜백이 마이크로 태스트 큐에 등록 (ㄴ)
- 메인 스크립트의 동기적인 부분이 모두 완료되면, 이벤트 루프가 마이크로 태스크 큐를 확인
- (ㄴ) 단계 : aaa(); 실행
- aaa()의 setTimeout 태스크큐에 등록 (ㄷ)
- ‘c’ 출력
- ‘b’ 출력
- 마이크로 태스크 큐 비워지면 이벤트 루프는 태스크 큐 확인
- (ㄱ) 단계 : ‘a’ 출력
- aaa() 함수를 호출하면서 setTimeout이 등록 (ㄹ)
- ‘c’ 출력
- (ㄱ) 단계 ‘d’ 출력
- (ㄹ) 단계 : ‘d’ 출력
결과: c -> b -> a -> c -> d -> d
[!note] Promise.resolve.then에서 aaa(); console.log(‘b’) 는 동기적으로 일어난다.
c가 출력되고, setTimeout의 콜백이 태스크 큐에 등록 된 후, b가 출력이 된다.
코드 예시 2
console.log('1');
setTimeout(function() {
console.log('2');
}, 0);
Promise.resolve()
.then(function() {
console.log('3');
})
.then(function() {
console.log('4');
});
console.log('5');
- 1 출력, 5출력
- setTimeout의 콜백을 태스크 큐에 등록 // 0초의 지연 시간 후에 태스크 큐에 추가.
- Promise.then의 콜백을 마이크로 태스크 큐에 등록
- 메인 스크립트의 동기 작업이 완료가 되면, 이벤트 루프는 마이크로 태스크 큐를 확인하고 그 안의 모든 작업을 처리한다.
- 3 출력
- 4 출력
- 메인 스크립트의 동기 작업이 완료가 되면, 이벤트 루프는 마이크로 태스크 큐를 확인하고 그 안의 모든 작업을 처리한다.
- 태스크 큐 확인 후 2출력
출력결과: 1 -> 5 -> 3 -> 4 -> 2
코드 예시 3
console.log('1');
setTimeout(function() {
console.log('2');
Promise.resolve().then(function() {
console.log('3');
});
}, 0);
Promise.resolve()
.then(function() {
console.log('4');
})
.then(function() {
console.log('5');
});
console.log('6');
- 1 출력, 6출력
- setTimeout 콜백이 태스크 큐에 등록 (2)
- 프로미스의 then 체인 콜백이 마이크로 태스크 큐에 등록 (4, 5)
- 이벤트 루프가 마이크로 태스크 큐를 확인
- 4, 5 출력
- 마지막으로 태스크 큐 확인하여 2 출력
- 그 후 새롭게 생성된 Promise가 마이크로 태스크 큐에 등록
- 3 출력
[!note] setTimeout 내부에 생성된 Promise 역시 해당 시점에서 가장 우선순위가 낮은 비동기 작업으로 처리된다.
출력 결과: 1 -> 6 -> 4 -> 5 -> 2 -> 3
코드 예시 4
function test() {
return new Promise((resolve, reject) => {
resolve();
console.log('step1');
})
}
test()
.then(() => {
console.log('step2')
})
.catch(() => {
console.log('error')
})
- test() 가 호출되고 프로미스 객체가 생성
- resolve() 실행 -> ‘step1’ 출력 // Promise 내부 함수는 마치 동기적으로 흐른다.
- then() 실행 -> ‘step2’
- 끝
결론: 비동기 작업은 규칙에 따라 처리 순서가 결정된다.
코드를 보고 알 수 있는 점?
JavaScript에서 비동기 작업은 정해진 규칙에 따라서 처리 순서가 결정이 되고,
이 규칙은 Promise(마이크로 태스크)와 setTimeout(태스트) 사이에서도 차별화 된다.
(혹시 틀린 정보가 있다면 댓글로 알려주세요!)
- 이 글은 옵시디언에서 작성되었습니다.
'[개발] > JavaScript' 카테고리의 다른 글
| JavaScript는 싱글 스레드 - 성능이 잘 나오는 이유는? (0) | 2023.12.30 |
|---|---|
| Web Storage API (0) | 2023.12.30 |
| 이벤트 (0) | 2023.07.15 |
| CommonJS is not going away (번역) (0) | 2023.07.06 |
| JavaScript SDK(JavaScript Software Development Kit) (0) | 2023.07.04 |