nextTick, setTimeout 및 setImmediate 세 가지 실행 순서

17659 단어 JS 기반면접
이 문제는 실행 순서와 이벤트 루프에 관한 것입니다.Event Loop과 작업 대기열 등 개념에 대해 제가 인용한 글을 먼저 읽을 수 있습니다. 본고는 주로 존재하는 의문점을 분석합니다.
다음은 전형적인 예입니다.
setImmediate(function(){
    console.log(1);
},0);
setTimeout(function(){
    console.log(2);
},0);
new Promise(function(resolve){
    console.log(3);
    resolve();
    console.log(4);
}).then(function(){
    console.log(5);
});
console.log(6);
process.nextTick(function(){
    console.log(7);
});
console.log(8);
// 3 4 6 8 7 5 2 1

출력 결과를 설명하기 전에 몇 가지 개념을 살펴보겠습니다.
macro-task: script(전체 코드), setTimeout, setInterval, setImmediate, I/O, UI rendering.micro-task: process.nextTick, Promise(네이티브), Object.observe,MutationObserver
script 전체 코드를 제외하고micro-task의 작업 우선순위는macro-task의 작업 우선순위보다 높습니다.그 중에서script(전체 코드)는 실행될 모든 코드로 이해할 수 있다.
그래서 실행 순서는 다음과 같다.
첫걸음.script 전체 코드가 실행됩니다. 실행 과정은
setImmediate macro-task 만들기
setTimeout macro-task 만들기
micro-task Promise를 생성합니다.then의 리셋을 실행하고script console를 실행합니다.log(3); resolve(); console.log(4); 이때 3과 4를 출력합니다. 리졸브가 호출되었지만 전체 코드가 실행되지 않아 Promise에 들어갈 수 없습니다.then 프로세스.
console.log(6) 출력 6
process.nextTick micro-task 만들기
console.log(8) 출력 8
첫 번째 프로세스가 끝나면 3468이 출력됩니다.
두 번째 단계.다른 micro-task의 우선순위가macro-task보다 높기 때문입니다.이때 micro-task에는 우선순위 프로세스에 따라 두 가지 작업이 있습니다.nextTick이 Promise보다 높습니다.그래서 먼저 7을 출력하고 5를 출력합니다.
세 번째 단계, micro-task 작업 목록은 이미 실행되었고, 집에서 내려와macro-task를 실행합니다.setTimeout의 우선순위가 setIImmediate보다 높기 때문에 먼저 2를 출력하고 1을 출력합니다.
전체 과정은 동기화 작업처럼 묘사되고 실제로는 Event Loop의 이벤트 순환을 바탕으로 한다.
micro-task와 macro-task의 실행 순서에 관해서는 아래의 예를 볼 수 있습니다.
// nextTick 
process.nextTick(function () {
    console.log('nextTick 1');
});
process.nextTick(function () { 
    console.log('nextTick 2');
});
//  setImmediate() 
setImmediate(function () {
    console.log('setImmediate 1'); 
    //   
    process.nextTick(function () {
        console.log(' ');
    });
});
setImmediate(function () {
    console.log('setImmediate 2'); 
});
 
console.log(' ');

책에서 제시한 실행 결과는 다음과 같다.
정상적으로 nextTick 지연 실행 1 nextTick 지연 실행 2 setImmediate 지연 실행 1 강세 삽입 setImmediate 지연 실행 2 프로세스.nextTick은 두 setImmediate 사이에 강제로 삽입되었습니다.그러나 이 코드를 실행하면 다음과 같은 결과가 나타납니다.
정상적으로 nextTick 지연 실행 1 nextTick 지연 실행 2 setImmediate 지연 실행 1 setImmediate 지연 실행 2 강세 박 선생님이 그 책을 쓰셨을 때 node 최신 버전은 0.10.13이었고 제 버전은 6입니다.x
이전 버전의 Node는 프로세스를 우선적으로 실행합니다.nextTick. 프로세스로 삼다.nextTick 대기열이 끝나면 setImmediate 작업을 수행합니다.그리고 다시 새로운 사건 순환으로 돌아간다.그래서 첫 번째 setImmediate를 실행하면 대기열에 첫 번째 setImmediate의 프로세스만 남습니다.nextTick 및 두 번째 setImmediate그래서 프로세스.nextTick이 먼저 실행됩니다.
새 버전의 Node에서 process.nextTick이 실행되면 setImmediate를 순환하고 setImmediate를 모두 실행한 후에 순환을 벗어납니다.그래서 두 개의 setImmediate가 실행된 후 대기열에는 첫 번째 setImmediate의 프로세스만 남았다.nextTick.마지막으로 강세 삽입을 출력합니다.
구체적인 구현은 Node를 참조하십시오.js 원본.
우선 순위에 대한 또 다른 명확한 버전:
관찰자 우선 순위
매번 교대 훈련 검사에서 각 관찰자의 우선순위는 다음과 같다.
idle 관찰자 > I/O 관찰자 > check 관찰자.
idle 관찰자:process.nextTick
I/O 관찰자: 네트워크, 파일, 데이터베이스 I/O 등 일반적인 I/O 리셋
check 관찰자: setImmediate, setTimeout
setImmediate 및 setTimeout 우선 순위
다음 예를 참조하십시오.
setImmediate(function () {
    console.log('1'); 
});
setTimeout(function () {
    console.log('2'); 
}, 0);
 
console.log('3');
 
// 3 2 1

우리는 현재 HTML5가 setTimeout의 최소 간격을 4ms로 규정하고 있다는 것을 알고 있다. 즉, 0은 실제로도 기본적으로 최소값 4ms로 설정하지 않는다는 것이다.저희가 이걸 딜레이를 늘려보도록 하겠습니다.
위에서 말한 set Timeout의 우선순위가 set Immediate보다 높다는 것은 사실 이런 견해는 조건이 있다.
다음 예를 보면 setTimeout에 20ms 지연 시간을 추가합니다.
setImmediate(function () {
    console.log('1'); 
});
setTimeout(function () {
    console.log('2'); 
}, 20);
 
console.log('3');
 
// 3 2 1

setTimeout은 20ms를 늦추고 실행하는데 setImmediate는 바로 실행하는데 2대 1을 먼저 출력하다니??
이 프로그램의 실행 시간을 인쇄해 보십시오.
// An highlighted block
var foo = 'bar';

프로그램 실행은 23ms를 사용했습니다. 즉, script(전체 코드)가 실행되기 전에setTimeout은 이미 유행이 지났기 때문에macro-task에 들어갈 때setTimeout은 여전히 setImmediate보다 우선합니다.만약 우리가 이 값을 좀 크게 조정한다면?
var t1 = +new Date();
setImmediate(function () {
    console.log('1'); 
});
setTimeout(function () {
    console.log('2'); 
},20);
 
console.log('3');
var t2 = +new Date();
console.log('time: ' + (t2 - t1));
// 
3 
time: 23 
2 
1

set Immediate는 set Timeout보다 먼저 실행되었습니다. macro-task 순환에 들어갈 때 set Timeout의 타이머가 아직 도착하지 않았기 때문입니다.
이상의 실험은 6.6.0 버전 Node에 기초한 것이다.js테스트, 실제로 이런 문제에 부딪혔을 때 가장 좋은 방법은 표준을 참고하고 원본을 조회하는 것이다. 개념과 순서를 외워서는 안 된다. 왜냐하면 표준도 변하기 때문이다.이 문장을 포함하여 또한 독학으로 총결하여 참고로 제공한다.

좋은 웹페이지 즐겨찾기