На этой странице

    Когда вы хотите выполнить какой-то кусок кода асинхронно, но как можно скорее, один из вариантов — использовать функцию setImmediate(), предоставляемую Node.js:

    setImmediate(() => {
      // выполнить что-то
    });

    Любая функция, переданная как аргумент setImmediate(), — это колбэк, который выполняется на следующей итерации event loop.

    Чем setImmediate() отличается от setTimeout(() => {}, 0) (с передачей таймаута 0 мс), а также от process.nextTick() и Promise.then()?

    Функция, переданная в process.nextTick(), выполнится на текущей итерации event loop, после завершения текущей операции. Это значит, что она всегда выполнится до setTimeout и setImmediate.

    Колбэк setTimeout() с задержкой 0 мс очень похож на setImmediate(). Порядок выполнения будет зависеть от разных факторов, но оба они выполнятся на следующей итерации event loop.

    Колбэк process.nextTick добавляется в process.nextTick queue. Колбэк Promise.then() добавляется в promises microtask queue. Колбэк setTimeout, setImmediate добавляется в macrotask queue.

    Event loop сначала выполняет задачи в process.nextTick queue, затем выполняет promises microtask queue, а затем выполняет macrotask queue.

    Вот пример, показывающий порядок между setImmediate(), process.nextTick() и Promise.then():

    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(), затем вызовет foo() из process.nextTick queue. После этого он обработает promises microtask queue, которая печатает bar и одновременно добавляет zoo() в process.nextTick queue. Затем он вызовет только что добавленный zoo(). В конце вызывается baz() из macrotask queue.

    Вышеописанный принцип верен для случаев CommonJS, но имейте в виду, что в ES-модулях, например в mjs-файлах, порядок выполнения будет другим:

    Так происходит потому, что загружаемый ES-модуль обёрнут как асинхронная операция, и таким образом весь скрипт фактически уже находится в promises microtask queue. Поэтому, когда промис немедленно разрешается, его колбэк добавляется в очередь microtask. Node.js попытается очистить эту очередь, прежде чем переходить к любой другой, а значит, вы увидите, что сначала выводится bar.