Skip to content

setImmediate() 이해하기

비동기적으로, 하지만 가능한 한 빨리 일부 코드를 실행하고 싶을 때, Node.js에서 제공하는 setImmediate() 함수를 사용하는 방법이 있습니다.

js
setImmediate(() => {
    // do something
})

setImmediate() 인수로 전달된 함수는 이벤트 루프의 다음 반복에서 실행되는 콜백입니다.

setImmediate()setTimeout(() => {}, 0) (0ms 타임아웃 전달)과 process.nextTick()Promise.then()과 어떻게 다를까요?

process.nextTick()에 전달된 함수는 현재 작업이 끝난 후 이벤트 루프의 현재 반복에서 실행됩니다. 즉, 항상 setTimeoutsetImmediate보다 먼저 실행됩니다.

0ms 지연의 setTimeout() 콜백은 setImmediate()와 매우 유사합니다. 실행 순서는 다양한 요인에 따라 달라지지만 둘 다 이벤트 루프의 다음 반복에서 실행됩니다.

process.nextTick 콜백은 process.nextTick 큐에 추가됩니다. Promise.then() 콜백은 promises 마이크로태스크 큐에 추가됩니다. setTimeout, setImmediate 콜백은 매크로태스크 큐에 추가됩니다.

이벤트 루프는 먼저 process.nextTick 큐의 작업을 실행하고, 그다음 promises 마이크로태스크 큐를 실행하고, 그다음 setTimeout 또는 setImmediate 매크로태스크 큐를 실행합니다.

다음은 setImmediate(), process.nextTick()Promise.then() 사이의 순서를 보여주는 예입니다.

js
const baz = () => console.log('baz');
const foo = () => console.log('foo');
const zoo = () => console.log('zoo');
const start = () => {
  console.log('start');
  setImmediate(baz);
  new Promise((resolve, reject) => {
    resolve('bar');
  }).then(resolve => {
    console.log(resolve);
    process.nextTick(zoo);
  });
  process.nextTick(foo);
};
start();
// start foo bar zoo baz

이 코드는 먼저 start()를 호출한 다음 process.nextTick 큐에서 foo()를 호출합니다. 그 후, promises 마이크로태스크 큐를 처리하여 bar를 출력하고 동시에 process.nextTick 큐zoo()를 추가합니다. 그런 다음 방금 추가된 zoo()를 호출합니다. 마지막으로 매크로태스크 큐baz()가 호출됩니다.

앞서 언급한 원칙은 CommonJS의 경우에 적용되지만, ES 모듈(예: mjs 파일)에서는 실행 순서가 다를 수 있습니다.

js
// start bar foo zoo baz

이는 로드되는 ES 모듈이 비동기 작업으로 래핑되어 있기 때문에 전체 스크립트가 실제로 이미 promises 마이크로태스크 큐에 있기 때문입니다. 따라서 프로미스가 즉시 해결되면 해당 콜백은 마이크로태스크 큐에 추가됩니다. Node.js는 다른 큐로 이동할 때까지 큐를 지우려고 시도하므로 먼저 bar가 출력되는 것을 볼 수 있습니다.