방금 Promises / A + 사양을 읽었으며 마이크로 태스크 및 매크로 태스크라는 용어를 발견했습니다. http://promisesaplus.com/#notes
이전에이 용어에 대해 들어 본 적이 없으며 이제 차이점이 무엇인지 궁금합니다.
나는 이미 웹에서 일부 정보를 찾으려고 노력했지만, 내가 찾은 것은 w3.org Archives (이 차이점을 설명하지는 않음) 의이 게시물입니다 .http : //lists.w3.org/Archives /Public/public-nextweb/2013Jul/0018.html
또한 “macrotask”라는 npm 모듈을 찾았습니다. https://www.npmjs.org/package/macrotask
또한 차이점이 정확히 무엇인지는 명확하지 않습니다.
내가 아는 것은 https://html.spec.whatwg.org/multipage/webappapis.html#task-queue
및 https : //html.spec.whatwg에 설명 된 것처럼 이벤트 루프와 관련이 있다는 것입니다 . .org / multipage / webappapis.html # perform-a-microtask-checkpoint
이 WHATWG 사양을 감안할 때 이론적으로 차이를 스스로 추출 할 수 있어야한다는 것을 알고 있습니다. 그러나 다른 사람들도 전문가의 짧은 설명으로 혜택을 볼 수 있다고 확신합니다.
답변
이벤트 루프의 한 번의 둘러보기 는 매크로 태스크 큐 에서 정확히 하나의 태스크를 처리합니다 (이 큐는 단순히 WHATWG 스펙 에서 태스크 큐 라고 함 ). 이 매크로 태스크가 완료되면 사용 가능한 모든 마이크로 태스크 가 처리됩니다 (즉, 동일한 처리주기 내에서). 이러한 마이크로 태스크는 처리되는 동안 마이크로 태스크 큐가 소진 될 때까지 더 많은 마이크로 태스크를 큐에 넣을 수 있습니다.
이것의 실제적인 결과는 무엇입니까?
마이크로 태스크가 다른 마이크로 태스크를 재귀 적으로 큐 에 넣는 경우 다음 매크로 태스크가 처리 될 때까지 시간이 오래 걸릴 수 있습니다. 즉, UI가 차단되거나 응용 프로그램에서 일부 유휴 I / O 유휴 상태가 될 수 있습니다.
그러나 적어도 Node.js의 process.nextTick 함수 ( 마이크로 태스크 를 대기열에 넣는 ) 와 관련하여 process.maxTickDepth 를 통해 이러한 차단에 대한 보호 기능이 내장되어 있습니다. 이 값은 기본값 인 1000으로 설정 되어이 한계에 도달 한 후 다음 매크로 태스크 를 처리 할 수있는 마이크로 태스크의 추가 처리를 줄입니다.
그래서 언제 무엇을 사용해야합니까?
기본적으로 비동기 방식으로 작업을 수행 해야하는 경우 (즉 , 가장 가까운 미래에이 (마이크로) 작업을 수행 한다고 말할 때 ) 마이크로 태스크를 사용하십시오 . 그렇지 않으면 macrotasks 를 고수하십시오 .
예
매크로 작업 : setTimeout , setInterval , setImmediate , requestAnimationFrame , I / O , UI 렌더링
마이크로 태스크 : process.nextTick , Promises , queueMicrotask , MutationObserver
답변
사양의 기본 개념 :
- 이벤트 루프에는 하나 이상의 작업 대기열이 있습니다 (작업 대기열은 매크로 작업 대기열입니다).
- 각 이벤트 루프에는 마이크로 태스크 대기열이 있습니다.
- 작업 대기열 = 매크로 작업 대기열! = 마이크로 작업 대기열
- 작업이 매크로 작업 대기열 또는 마이크로 작업 대기열로 푸시 될 수 있습니다
- 작업이 대기열 (마이크로 / 매크로)로 푸시되면 작업 준비가 완료되었음을 의미하므로 작업을 지금 실행할 수 있습니다.
이벤트 루프 프로세스 모델은 다음과 같습니다.
때 호출 스택이 비어의 steps-을
- 작업 대기열에서 가장 오래된 작업 (작업 A)을 선택하십시오.
- 작업 A가 null 인 경우 (작업 대기열이 비어 있음을 의미) 6 단계로 건너 뜁니다.
- “현재 실행중인 작업”을 “작업 A”로 설정
- “태스크 A”실행 (콜백 함수 실행을 의미)
- “현재 실행중인 작업”을 null로 설정하고 “작업 A”를 제거하십시오.
- 마이크로 태스크 대기열 수행
- (a). 마이크로 작업 대기열에서 가장 오래된 작업 (작업 x)을 선택합니다
- (b). 작업 x가 null 인 경우 (마이크로 작업 대기열이 비어 있음을 의미) 단계 (g)로 점프
- (c). “현재 실행중인 작업”을 “task x”로 설정
- (d) .run “작업 x”
- (e). “현재 실행중인 작업”을 null로 설정하고 “task x”를 제거하십시오.
- (f). 마이크로 태스킹 대기열에서 다음으로 오래된 작업을 선택하고 단계 (b)로 이동
- (g). 마무리 마이크로 태스크 큐;
- 1 단계로 이동하십시오.
단순화 된 프로세스 모델은 다음과 같습니다.
- 매크로 작업 대기열에서 가장 오래된 작업을 실행 한 다음 제거하십시오.
- 사용 가능한 모든 작업을 마이크로 태스킹 대기열에서 실행 한 다음 제거하십시오.
- 다음 라운드 : 매크로 작업 대기열에서 다음 작업 실행 (점프 2 단계)
기억해야 할 것 :
- 매크로 작업 대기열에있는 작업이 실행 중이면 새로운 이벤트가 등록 될 수 있으므로 새로운 작업이 생성 될 수 있습니다.
- promiseA.then ()의 콜백은 작업입니다
- promiseA가 해결 / 거부 됨 : 현재 이벤트 루프 라운드에서 작업이 마이크로 태스크 대기열로 푸시됩니다.
- promiseA 보류 중 : 향후 이벤트 루프 라운드에서 작업이 마이크로 태스크 대기열로 푸시됩니다 (다음 라운드 일 수 있음)
- setTimeout (callback, n)의 콜백은 작업이며, n이 0 인 매크로 작업 대기열로 푸시됩니다.
- promiseA.then ()의 콜백은 작업입니다
- 마이크로 태스킹 대기열의 작업은 현재 라운드에서 실행되는 반면, 매크로 태스크 대기열의 작업은 다음 라운드의 이벤트 루프를 기다려야합니다.
- 우리는 모두 “클릭”, “스크롤”, “ajax”, “setTimeout”의 콜백을 알고 있습니다. 그러나 스크립트 태그에서 전체적으로 js 코드도 기억해야합니다 (매크로 태스크).
답변
스택과 분리하여 이벤트 루프에 대해 논의 할 수 없다고 생각합니다.
JS에는 세 개의 “스택”이 있습니다.
- 모든 동기 호출에 대한 표준 스택 (한 함수가 다른 함수를 호출하는 등)
- 우선 순위가 높은 모든 비동기 작업 (process.nextTick, Promises, Object.observe, MutationObserver)에 대한 마이크로 태스크 대기열 (또는 작업 큐 또는 마이크로 태스크 스택 )
- 우선 순위가 낮은 모든 비동기 작업 (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, UI 렌더링)에 대한 매크로 작업 대기열 (또는 이벤트 대기열, 작업 대기열, 매크로 작업 대기열 )
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
그리고 이벤트 루프는 다음과 같이 작동합니다.
- 스택에서 맨 아래부터 맨 위까지 모든 것을 실행하고 스택이 비어있을 때만 위의 대기열에서 무슨 일이 일어나고 있는지 확인하십시오.
- 마이크로 스택을 확인하고 스택의 도움으로 모든 작업을 실행하십시오 (필요한 경우). 마이크로 작업 대기열이 비어 있거나 실행이 필요하지 않을 때까지 한 번에 한 번의 작업으로 매크로 스택을 확인하십시오.
- 매크로 스택을 확인하고 스택의 도움으로 필요한 경우 모든 것을 실행하십시오.
스택이 비어 있지 않으면 Mico 스택이 닿지 않습니다. 마이크로 스택이 비어 있지 않거나 실행이 필요하지 않으면 매크로 스택은 건드리지 않습니다.
요약하자면, 마이크로 태스킹 큐는 매크로 태스크 큐와 거의 동일하지만 해당 태스크 (process.nextTick, Promises, Object.observe, MutationObserver) 는 매크로 태스크 보다 우선 순위가 높습니다.
마이크로는 매크로와 비슷하지만 우선 순위가 높습니다.
여기에 모든 것을 이해하기위한 “궁극적 인”코드가 있습니다.
console.log('stack [1]');
setTimeout(() => console.log("macro [2]"), 0);
setTimeout(() => console.log("macro [3]"), 1);
const p = Promise.resolve();
for(let i = 0; i < 3; i++) p.then(() => {
setTimeout(() => {
console.log('stack [4]')
setTimeout(() => console.log("macro [5]"), 0);
p.then(() => console.log('micro [6]'));
}, 0);
console.log("stack [7]");
});
console.log("macro [8]");
/* Result:
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4]
micro [6]
stack [4]
micro [6]
stack [4]
micro [6]
macro [5], macro [5], macro [5]
--------------------
but in node in versions < 11 (older versions) you will get something different
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4], stack [4], stack [4]
micro [6], micro [6], micro [6]
macro [5], macro [5], macro [5]
more info: https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3
*/