[javascript] 즉시 대 nextTick 설정

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

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

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



답변

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

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


답변

그림으로

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에 관한 최고의 책)


답변

나는 이것을 아주 잘 설명 할 수 있다고 생각한다. 이후로는 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가 성숙 해지고 사람들이 기존 인터페이스에 의존하게되면 얻을 수있는 것입니다.


답변

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

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

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

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


답변

간단히 말해서, 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

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


답변

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

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

언제 사용 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()하는 모든 경우에 “.


답변

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

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

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

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

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