즉시 대 nextTick 설정


336

Node.js 버전 0.10이 오늘 릴리스되어 도입되었습니다 setImmediate. API 변경의 문서는 재귀 할 때 그것을 사용하는 제안 nextTick전화를.

MDN이 말한 것과는 매우 유사합니다 process.nextTick.

언제 사용 nextTick하고 언제 사용해야 setImmediate합니까?



1
성능 벤치 마크 에서 큰 계산 nextTick보다 빠릅니다 setImmediate.

10
기록을 위해, 나는이 5 개의 문단을 먼저 읽었고, 실제로 나를 위해 아무것도 명확하게하지 않았을 때이 질문을 끝냈습니다. 허용되는 답변은 훨씬 간결하며 실제로 setImmediate더 자세한 내용을 설명합니다.
Chev

블로그 에서 차이점을 자세히 설명했습니다 .
plaper

GC가 전에는 가능 setImmediate하지만 전에는 그렇지 nextTick않습니까?

답변:


510

setImmediate이미 이벤트 큐에있는 I / O 이벤트 콜백 뒤에 함수를 큐에 넣으려면 사용하십시오 . process.nextTick현재 기능이 완료된 직후에 실행되도록 이벤트 대기열의 헤드에서 기능을 효과적으로 대기열에 넣는 데 사용 합니다.

따라서 재귀를 사용하여 오래 실행되는 CPU 바운드 작업을 중단하려는 경우 이제는 I / O 이벤트 콜백이 기회를 얻지 못하므로 다음 반복을 대기열에 넣는 setImmediate대신 사용하려고합니다. process.nextTick반복 사이에서 실행합니다.


86
process.nextTick에 전달 된 콜백은 일반적으로 현재 실행 흐름이 끝날 때 호출되므로 함수를 동 기적으로 호출하는 것만 큼 빠릅니다. 선택하지 않으면 이벤트 루프가 고갈되어 I / O가 발생하지 않습니다. setImmediates는 작성된 순서대로 큐에 넣고 루프 반복마다 큐에서 한 번 팝됩니다. 이것은 process.nextTick과는 다릅니다. process.maxTickDepth는 반복 당 대기 콜백을 실행합니다. setImmediate는 대기중인 콜백을 발생시킨 후 이벤트 루프를 발생시켜 I / O가 고갈되지 않도록합니다.
Benjamin Gruenbaum

2
@UstamanSangat setImmediate는 IE10 +에서만 지원되며 다른 모든 브라우저는 Microsoft가이기는 것을 좋아하지 않기 때문에 미래의 표준을 구현하는 것을 완고 히 거부합니다. FF / Chrome에서 비슷한 결과를 얻으려면 postMessage (메시지를 자신의 창에 게시)를 사용하면됩니다. 특히 업데이트가 UI 관련 인 경우 requestAnimationFrame 사용을 고려할 수 있습니다. setTimeout (func, 0)은 process.nextTick처럼 전혀 작동하지 않습니다.
fabspro

45
@fabspro "마이크로 소프트를 구타하는 것을 좋아하지 않기 때문에"무언가에 대해 아프게 들린다. 주로 끔찍하고 이름이 지어 졌기 때문입니다. setImmediate 함수가 한 번만 실행되면 절대 실행되지 않습니다. 함수의 이름은 기능과 정반대입니다. nextTick과 setImmediate는 전환하는 것이 더 좋습니다. setImmediate는 현재 스택이 완료된 직후 (I / O 대기 전) 실행되고 nextTick은 다음 틱 종료시 (I / O 대기 후) 실행됩니다. 그러나 이것은 이미 천 번 언급되었습니다.
Craig Andrews

4
@fabspro 그러나 불행히도이 함수는 nextTick이라고합니다. nextIick은 "즉시"실행되며 setImmediate는 setTimeout / postMessage와 유사합니다.
Robert

1
@CraigAndrews requestAnimationFrame항상 발생하지 않기 때문에 피할 것입니다 (확실히 보았습니다. 예는 탭이 현재 탭이 아니라고 생각합니다). 페이지가 그림을 완료하기 전에 호출 될 수 있습니다 (예 : 브라우저는 여전히 그림 그리기 중입니다).
robocat

68

그림으로

import fs from 'fs';
import http from 'http';

const options = {
  host: 'www.stackoverflow.com',
  port: 80,
  path: '/index.html'
};

describe('deferredExecution', () => {
  it('deferredExecution', (done) => {
    console.log('Start');
    setTimeout(() => console.log('TO1'), 0);
    setImmediate(() => console.log('IM1'));
    process.nextTick(() => console.log('NT1'));
    setImmediate(() => console.log('IM2'));
    process.nextTick(() => console.log('NT2'));
    http.get(options, () => console.log('IO1'));
    fs.readdir(process.cwd(), () => console.log('IO2'));
    setImmediate(() => console.log('IM3'));
    process.nextTick(() => console.log('NT3'));
    setImmediate(() => console.log('IM4'));
    fs.readdir(process.cwd(), () => console.log('IO3'));
    console.log('Done');
    setTimeout(done, 1500);
  });
});

다음과 같은 출력을 줄 것입니다

Start
Done
NT1
NT2
NT3
TO1
IO2
IO3
IM1
IM2
IM3
IM4
IO1

이것이 차이점을 이해하는 데 도움이되기를 바랍니다.

업데이트 :

process.nextTick()setImmediate ()를 사용하면 다른 I / O 이벤트가 시작되기 전에 실행이 지연된 콜백 이 이미 대기열에있는 I / O 이벤트 뒤에 대기합니다.

Mario Casciaro의 Node.js 디자인 패턴 (아마도 node.js / js에 관한 최고의 책)


2
정말 도움이됩니다. 이미지와 예제가 무언가를 이해하는 가장 빠른 방법이라고 생각합니다.
John James

1
I / O 사이클 내에 있지 않을 때 setTimeout () 및 setImmediate ()가 프로세스의 성능에 따라 순서가 결정적이지 않다고 지적하는 것이 중요하다고 생각합니다. nodejs.org/en/docs/guides/event-loop-timers-and-nexttick 따라서이 For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process: 답변은 정확한 차이점에 대한 답변이 아니라 다른 상황에서 달라질 수있는 예일뿐입니다.
Actung

@Actung이 지적했듯이. 결과를 판별하려면 setTimetout 및 setImmediate가 I / O주기 내에 있는지 여부를 아는 것이 매우 중요합니다.
Rajika Imal

50

나는 이것을 아주 잘 설명 할 수 있다고 생각한다. 이후로는 nextTick재귀 적으로 호출하면 계속에서 이벤트 루프를 차단 끝낼 수, 현재 작업의 끝에서 호출됩니다. setImmediate이벤트 루프의 점검 단계에서 실행하여 이벤트 루프가 정상적으로 계속되도록하여이를 해결합니다.

   ┌───────────────────────┐
┌─>│        timers         
  └──────────┬────────────┘
  ┌──────────┴────────────┐
       I/O callbacks     
  └──────────┬────────────┘
  ┌──────────┴────────────┐
       idle, prepare     
  └──────────┬────────────┘      ┌───────────────┐
  ┌──────────┴────────────┐         incoming:   
           poll          │<─────┤  connections, 
  └──────────┬────────────┘         data, etc.  
  ┌──────────┴────────────┐      └───────────────┘
          check          
  └──────────┬────────────┘
  ┌──────────┴────────────┐
└──┤    close callbacks    
   └───────────────────────┘

출처 : https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

점검 단계는 폴링 단계 직후에 있습니다. 이는 폴링 단계 및 I / O 콜백이 호출 setImmediate이 실행될 가능성이 가장 높기 때문 입니다. 따라서 이상적으로는 대부분의 호출이 nextTick모든 작업 후 확인되고 기술적으로 이벤트 루프 외부에 존재하는 것만 큼 ​​즉각적이지는 않습니다 .

의 사이의 차이의 약간의 예를 살펴 보자 setImmediateprocess.nextTick:

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from setImmediate handler.
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
  });
}
step(0);

방금이 프로그램을 실행했고 이벤트 루프의 첫 번째 반복을 단계별로 실행한다고 가정 해 봅시다. step반복 0으로 함수를 호출 합니다. 그런 다음 하나에 대한 처리기와 두 개의 처리기를 등록 setImmediate합니다 process.nextTick. 그런 다음 setImmediate다음 점검 단계에서 실행될 핸들러 에서이 함수를 재귀 적으로 호출합니다 . nextTick핸들러는이 두 번째 등록 된 실제로 처음 실행 순간에도, 이벤트 루프를 중단 현재 작업의 끝에서 실행됩니다.

순서는 다음과 같습니다. nextTick현재 작업이 종료되면 발생하고 다음 이벤트 루프가 시작되고 정상 이벤트 루프 단계가 실행되고 setImmediate실행되고 재귀 적으로 호출 step되어 프로세스를 다시 시작합니다. 현재 작동 종료, nextTick화재 등

위 코드의 결과는 다음과 같습니다.

nextTick iteration: 0
setImmediate iteration: 0
nextTick iteration: 1
setImmediate iteration: 1
nextTick iteration: 2
setImmediate iteration: 2
nextTick iteration: 3
setImmediate iteration: 3
nextTick iteration: 4
setImmediate iteration: 4
nextTick iteration: 5
setImmediate iteration: 5
nextTick iteration: 6
setImmediate iteration: 6
nextTick iteration: 7
setImmediate iteration: 7
nextTick iteration: 8
setImmediate iteration: 8
nextTick iteration: 9
setImmediate iteration: 9

이제 재귀 호출을 핸들러 대신 핸들러 step로 옮깁니다 .nextTicksetImmediate

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from nextTick handler.
  });
}
step(0);

이제 재귀 호출을 핸들러 step로 옮겼으므로 nextTick다른 순서로 동작합니다. 이벤트 루프의 첫 반복은 핸들러뿐만 아니라 핸들러 step등록을 호출하고 호출 합니다. 현재 작업이 끝나면 처리기가 실행되어 다른 처리기뿐만 아니라 다른 처리기 를 재귀 적으로 호출 하고 등록 합니다. 현재 작업 후에 처리기가 실행 되므로 처리기 내에 처리기를 등록 하면 현재 처리기 작업이 완료된 직후 두 번째 처리기가 실행됩니다. 핸들러는 지금까지 계속에서 현재 이벤트 루프를 방지 발사를 유지합니다. 우리는 우리의 모든 것을 통해 얻을 것이다setImmedaitenextTicknextTickstepsetImmediatenextTicknextTicknextTicknextTicknextTicknextTick처리기 하나를보기 전에 setImmediate처리기.

위 코드의 결과는 다음과 같습니다.

nextTick iteration: 0
nextTick iteration: 1
nextTick iteration: 2
nextTick iteration: 3
nextTick iteration: 4
nextTick iteration: 5
nextTick iteration: 6
nextTick iteration: 7
nextTick iteration: 8
nextTick iteration: 9
setImmediate iteration: 0
setImmediate iteration: 1
setImmediate iteration: 2
setImmediate iteration: 3
setImmediate iteration: 4
setImmediate iteration: 5
setImmediate iteration: 6
setImmediate iteration: 7
setImmediate iteration: 8
setImmediate iteration: 9

우리가 재귀 호출을 중단하지 않고 10 회 반복 후에 호출을 중단했다면 nextTick호출은 계속 재귀 하고 이벤트 루프가 다음 단계를 계속하지 못하게합니다. 이것은 nextTick재귀 적으로 사용될 때 블로킹 될 수있는 반면 setImmediate다음 이벤트 루프 setImmediate에서 발생하고 하나에서 다른 핸들러를 설정 하면 현재 이벤트 루프가 전혀 중단되지 않으므로 정상적으로 이벤트 루프의 단계를 계속 실행할 수 있습니다.

희망이 도움이됩니다!

추신-나는 다른 주석에 동의합니다. 두 함수의 이름은 nextTick현재 이벤트의 끝이 아니라 다음 이벤트 루프에서 발생하는 것처럼 들리기 때문에 두 함수의 이름을 쉽게 바꿀 수 있으며 현재 루프의 끝이 더 "즉시" "는 다음 루프의 시작보다. API가 성숙 해지고 사람들이 기존 인터페이스에 의존하게되면 얻을 수있는 것입니다.


2
꽤 명확한 설명. 이 답변에는 더 많은 투표가 필요하다고 생각합니다.
Actung

음 (Y) 설명
Dhiraj 샤르마

process.nextTick 사용에 대한 Node의 경고를 반복하는 것이 중요합니다. nextTickQueue에서 많은 수의 콜백을 대기열에 넣는 경우 폴링 단계에 도달하지 않도록하여 이벤트 루프가 고갈 될 수 있습니다. 이것이 일반적으로 setImmediate를 선호하는 이유입니다.
faridcs

1
감사합니다. 이것이 가장 좋은 설명이었습니다. 샘플 코드가 실제로 도움이되었습니다.
skyhavoc

@skyhavoc 내가 도와 줄 수있어서 기쁘다!
Chev

30

답변의 의견에서 nextTick이 Macrosemantics에서 Microsemantics로 전환되었다고 명시 적으로 언급하지는 않습니다.

노드 0.9 이전 (setImmediate가 소개 될 때)에 nextTick은 다음 콜 스택의 시작에서 작동했습니다.

노드 0.9부터 nextTick은 기존 호출 스택의 끝에서 작동하는 반면 setImmediate는 다음 호출 스택의 시작에 있습니다

도구 및 세부 정보는 https://github.com/YuzuJS/setImmediate 를 확인 하십시오.


11

간단히 말해서, process.NextTick ()은 이벤트 루프의 다음 틱에서 실행됩니다. 그러나 setImmediate에는 기본적으로 별도의 단계가 있으므로 setImmediate ()에 등록 된 콜백이 IO 콜백 및 폴링 단계 후에 만 ​​호출됩니다.

좋은 설명을 보려면 이 링크를 참조하십시오 : https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and -그 메트릭스 -c4907b19da4c

단순화 된 이벤트 루프 이벤트


8

두 가지 작동 방식을 자세히 설명하는 훌륭한 답변입니다.

특정 질문에 대한 답변 만 추가하면됩니다.

언제 사용 nextTick하고 언제 사용해야 setImmediate합니까?


항상 사용하십시오 setImmediate.


Node.js를 이벤트 루프, 타이머 및process.nextTick() 문서는 다음을 포함한다 :

setImmediate()추론하기 쉽기 때문에 개발자 는 모든 경우에 사용하는 것이 좋습니다 (브라우저 JS와 같이 더 광범위한 환경과 호환되는 코드로 이어집니다).


이 문서의 앞부분은 다음과 같은 경고로 process.nextTick이어질 수 있다고 경고합니다 .

재귀를 process.nextTick()호출 하여 I / O를 "고갈"시킬 수 있기 때문에 일부 나쁜 상황 은 이벤트 루프가 폴링 단계 에 도달하지 못하게합니다 .

결과적으로 process.nextTick굶어 죽을 수도 있습니다 Promises.

Promise.resolve().then(() => { console.log('this happens LAST'); });

process.nextTick(() => {
  console.log('all of these...');
  process.nextTick(() => {
    console.log('...happen before...');
    process.nextTick(() => {
      console.log('...the Promise ever...');
      process.nextTick(() => {
        console.log('...has a chance to resolve');
      })
    })
  })
})

반면에, setImmediate이다 " 에 대한 이유에보다 쉽게 "및 이러한 유형의 문제를 피할 수 :

Promise.resolve().then(() => { console.log('this happens FIRST'); });

setImmediate(() => {
  console.log('this happens LAST');
})

그래서의 독특한 행동에 대한 특정 필요가 없다면 process.nextTick, 권장되는 접근 방식 "에 있습니다 사용 setImmediate()하는 모든 경우에 ".


1

더 나은 이해를 위해 루프 전용 문서 섹션 을 확인하는 것이 좋습니다 . 거기에서 가져온 일부 스 니펫 :

사용자와 관련하여 비슷한 두 가지 전화가 있지만 이름이 혼동됩니다.

  • process.nextTick ()은 같은 단계에서 즉시 발생합니다

  • setImmediate ()는
    이벤트 루프 의 다음 반복 또는 '틱'에서 발생합니다.

본질적으로 이름을 바꿔야합니다. process.nextTick ()은 setImmediate ()보다 더 빨리 실행되지만 이것은 변경되지 않는 과거의 아티팩트입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.