Promise.resolve().then vs setImmediate vs nextTick

NodeJS 0.11, а также io.js и ветка Node 0.12 поставляются с нативными промисами.

Нативные промисы имеют .thenметод, который всегда выполняется в будущем цикле цикла событий.

До сих пор я использовал setImmediate для постановки в очередь на следующую итерацию цикла событий с тех пор, как перешел с nextTick< /а>:

setImmediate(deferThisToNextTick); // My NodeJS 0.10 code
process.nextTick(deferThisToNextTick); // My NodeJS 0.8 code

Поскольку теперь у нас есть новый способ сделать это:

Promise.resolve().then(deferThisToNextTick); 

Что я должен использовать? Кроме того, действует ли Promise.resolve.then как setImmediate или как nextTick в отношении кода, выполняемого до или после цикла обработки событий?


person Benjamin Gruenbaum    schedule 25.12.2014    source источник
comment
Делюсь некоторыми исследованиями: в Chromium — обещание ставит в очередь микрозадачу, здесь выполняется микрозадача github.com/yoavweiss/Blink/blob/ вызывается здесь, когда приходит или проверяется скрипт, но скрипт не запущен: github.com/yoavweiss/Blink/blob/   -  person Benjamin Gruenbaum    schedule 25.12.2014
comment
Разрешение промисов github.com/joyent/node/ blob/ — вызывает github. com/joyent/node/blob/ — получает github.com/joyent/node/blob/   -  person Benjamin Gruenbaum    schedule 25.12.2014
comment
Очень похоже: github.com/joyent/node/issues/7714   -  person Benjamin Gruenbaum    schedule 25.12.2014
comment
Больше соуса: github.com/joyent/node/blob /v0.12/src/node.js#L305   -  person Benjamin Gruenbaum    schedule 25.12.2014
comment
Проверенные микрозадачи выполняются в очереди nextTick: github. com/joyent/node/blob/v0.12/src/node.js#L326-L329 , я подожду несколько часов, чтобы узнать, захочет ли член команды v8 или node уточнить, а если нет, то я напишите мой ответ.   -  person Benjamin Gruenbaum    schedule 25.12.2014
comment
Вы можете поделиться этим вопросом в обсуждении на github, чтобы они могли прийти сюда и ответить.   -  person thefourtheye    schedule 25.12.2014


Ответы (3)


Использование Promise.resolve().then не имеет преимуществ перед nextTick. Он выполняется в той же очереди, но имеет немного более высокий приоритет, то есть обработчик обещаний может предотвратить запуск обратного вызова следующего тика, обратное невозможно. Это поведение является деталью реализации, и на него нельзя полагаться.

Promise.resolve().then явно медленнее (я думаю, намного), потому что создает два промиса, которые будут отброшены.

Подробную информацию о реализации можно найти здесь: https://github.com/joyent/node/pull/8325

Самая важная часть: Promise.resolve().then похож на nextTick, а не на setImmediate. Использование его вместо setImmediate может кардинально изменить поведение вашего кода.

person vkurchatkin    schedule 25.12.2014
comment
Проголосовал. Я хотел бы увидеть пример для последнего абзаца. - person thefourtheye; 25.12.2014
comment
Спасибо, это звучит правильно, и то, что я тоже заметил в коде. Было бы неплохо, если бы вы могли уточнить, когда их использовать и почему это работает именно так. @thefourtheye любой пример того, где nextTick не будет работать вместо setImmediate - и Promise.resolve().then тоже не будет - person Benjamin Gruenbaum; 25.12.2014
comment
Я имею в виду, что вы вообще не должны использовать Promise.resolve().then. Этот трюк ничего не дает. Относительно nextTick vs setImmediate есть много информации - person vkurchatkin; 25.12.2014
comment
Он выполняется в той же очереди, но имеет чуть более высокий приоритет... На самом деле, не совсем так. Каждый из них имеет свой собственный механизм обработки очереди обратных вызовов. - person Trevor Norris; 30.12.2014
comment
Ну, очередь микрозадач сбрасывается внутрь очереди nextTick, это я и имел в виду. Намерение состояло в том, чтобы заставить это вести себя как одна очередь, насколько это возможно. - person vkurchatkin; 31.12.2014
comment
@vkurchatkin, почему это создает два обещания? Promise.resolve().then явно медленнее (я думаю, намного), потому что создает два обещания, которые будут отброшены? - person human; 16.04.2020
comment
Promise.resolve() создает первый, .then() создает второй - person vkurchatkin; 16.04.2020

Я не буду отвечать на выделенную полужирным шрифтом техническую часть, а только на вопрос

Что я должен использовать?

Я не думаю, что есть какая-то причина использовать Promise.resolve().then(), если только вы не заинтересованы в обещании результата вашей асинхронно выполняемой функции. Конечно, если вы да, то это будет намного лучше, чем иметь дело с адом обратных вызовов или делать new Promise из setTimeout или nextTick.

Есть и второе техническое отличие, более важное, чем время: промисы поглощают исключения. Чего вы, вероятно, не хотите. Итак, как упомянул @vkurchatkin, не создавайте обещаний только для того, чтобы их выбросить. Не только потому, что это медленнее, но и потому, что это делает ваш код менее читаемым, а ваше приложение более подверженным ошибкам.

person Bergi    schedule 25.12.2014

Promise.resolve будет разрешен сразу (синхронно), а setImmediate явно сразу после выполнения текущего события.

person Ilia Sidorenko    schedule 03.07.2017
comment
Попробуйте это в консоли браузера, чтобы убедиться, что вы не правы: Promise.resolve([]).then(function(){ console.log('1'); }); console.log('2'); - person Martin Konecny; 01.11.2017
comment
Я думаю, вы путаете его с новым Promise((res, rej) => res());. Приведенный выше пример new Promise((res) => { console.log(1); res(); }); console.log(2);. В этом случае 1 будет напечатано раньше 2. - person Trenskow; 06.07.2020