2013-03-11 3 views
268

Node.js версия 0.10 была выпущена сегодня и была представлена ​​setImmediate. Документация API changes предлагает использовать ее при выполнении рекурсивных вызовов nextTick.setImmediate vs. nextTick

От MDN says кажется очень похожим на process.nextTick.

Когда следует использовать nextTick и когда следует использовать setImmediate?

+17

Есть 5 пунктов об этом изменении в блоге http://blog.nodejs.org/2013/03/11/node -v0-10-0-stable/ – mak

+1

Из тестов производительности выглядит так: 'nextTick' быстрее, чем' setImmediate' при больших вычислениях. – 2014-06-02 20:13:29

+8

Для записи я сначала прочитал эти пять абзацев и до сих пор оставался в этом вопросе, когда на самом деле я ничего не понял. Принятый ответ гораздо более краток и фактически описывает, что «setImmediate» делает более подробно. – Chev

ответ

416

Используйте setImmediate, если вы хотите поставить в очередь функцию за любыми обратными вызовами событий ввода-вывода, которые уже находятся в очереди событий. Используйте process.nextTick для эффективной очереди функции в начале очереди событий, чтобы она выполнялась сразу же после завершения текущей функции.

Таким образом, в случае, когда вы пытаетесь разбить длинный ход, CPU переплете работу с помощью рекурсии, вы теперь хотите использовать setImmediate, а не process.nextTick в очереди на следующей итерации как в противном случае любые обратные вызовы событий ввода/вывода не будет иметь шансов работать между итерациями.

+0

Почему бы мне не использовать process.nextTick все время? Надеюсь, ты ответишь, все это следующее. Благодарю. –

+69

Обратные вызовы, переданные процессу.nextTick обычно вызывается в конце текущего потока выполнения и, таким образом, примерно так же быстро, как вызов функции синхронно. Неконтролируемый левый, это будет голодать цикл событий, предотвращая появление каких-либо операций ввода-вывода. setImmediates помещаются в очередь в созданном порядке и выгружаются из очереди один раз за итерацию цикла. Это отличается от process.nextTick, который выполнит обратные вызовы process.maxTickDepth для каждой итерации. setImmediate приведет к циклу событий после запуска очереди в обратном порядке, чтобы убедиться, что I/O не голодает. –

+0

В мире браузера setTimeout (func, 0) работает как process.nextTick(), но нет эквивалента для setImmediate(). Мне, однако, сказали, что поведение process.nextTick() изменилось, не так ли? –

29

В комментариях в ответе он явно не указывает, что nextTick переместился с Macrosemantics на Microsemantics.

до узла 0,9 (когда был установлен setImmediate), nextTick работал в начале следующего стоп-кадра.

начиная с узлом 0.9, nextTick работает в конце существующего стека вызовов, тогда как setImmediate находится в начале следующего стека вызовов

выписки https://github.com/YuzuJS/setImmediate для инструментов и детали

26

В качестве иллюстрации

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 

Надеюсь, это поможет понять разницу.

+0

Это действительно полезно. Я думаю, что образы и примеры - это самый быстрый способ понять что-то. –

13

Я думаю, что я могу проиллюстрировать это довольно красиво. Так как 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/

Обратите внимание, что фаза проверки сразу после этапа опроса. Это связано с тем, что наиболее часто встречаются фаны опроса и обратные вызовы ввода-вывода, и ваши вызовы будут выполняться до setImmediate. Поэтому в идеале большинство этих вызовов на самом деле будут довольно быстрыми, а не так быстро, как nextTick, который проверяется после каждой операции и технически существует вне цикла событий.

Давайте посмотрим на небольшой пример разницы между setImmediate и process.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 с нулевой итерацией. Затем он зарегистрирует два обработчика, один для 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 в наш nextTick обработчик вместо setImmediate.

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 регистрацию обработчика setImmedaite, а также обработчик nextTick. После завершения текущей операции наши обработчики обработчика nextTick, которые рекурсивно набирают step и регистрируют другой обработчик setImmediate, а также другой обработчик nextTick. Поскольку обработчик nextTick срабатывает после текущей операции, регистрация обработчика nextTick в обработчике nextTick приведет к тому, что второй обработчик будет запущен сразу же после завершения текущей операции обработчика. Обработчики nextTick будут продолжать стрельбу, предотвращая непрерывность текущего цикла событий. Мы проверим всех наших обработчиков nextTick, прежде чем мы увидим один огненный обработчик 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 изнутри не будет прерывать текущий цикл событий вообще, позволяя ему продолжать выполнение фаз цикла событий как обычно ,

Надеюсь, что это поможет!

PS - Я согласен с другими комментаторами в том, что имена двух функций могут быть легко заменены, так как nextTick звучит так, как будто он загорается в следующем цикле событий, а не в конце текущего, а конец текущего цикл является более «немедленным», чем начало следующего цикла. Ну, это то, что мы получаем по мере созревания API, и люди зависят от существующих интерфейсов.

3

Простым термином 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-its-metrics-c4907b19da4c

simplified event loop events

Смежные вопросы