Разница между микрозадачей и макрозадачей в контексте цикла событий
Я только что закончил читать спецификацию Promises/A + и наткнулся на термины microtask и macrotask: см. http://promisesaplus.com/#notes
Я никогда не слышал об этих условиях раньше, и теперь мне любопытно, какая разница?
Я уже пытался найти некоторую информацию в Интернете, но все, что я нашел, - это сообщение из архивов w3.org(что не объясняет мне разницу): http://lists.w3.org/Archives/Public/public-nextweb/2013Jul/0018.html
Кроме того, я нашел модуль npm под названием "macrotask": https://www.npmjs.org/package/macrotask
Опять же, не выяснено, какая разница в точности.
Все, что я знаю, это то, что оно имеет какое-то отношение к циклу событий, как описано в https://html.spec.whatwg.org/multipage/webappapis.html#task-queue
и https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
Я знаю, что теоретически я должен сам извлечь различия, учитывая эту спецификацию WHATWG. Но я уверен, что другие могут извлечь выгоду из короткого объяснения, данного экспертом.
Ответы
Ответ 1
В одном из циклов события будет выполняться только одна задача из очереди макросов (эта очередь просто называется очередью задач в спецификация WHATWG).
По завершении этой макрозадачи будут обработаны все доступные микротаски, а именно в пределах одного цикла цикла. Хотя эти микротовары обрабатываются, они могут ставить в очередь еще больше микротоков, которые будут запускаться один за другим, пока очередь микроточек не будет исчерпана.
Каковы практические последствия этого?
Если microtask рекурсивно ставит в очередь другие микротаски, это может занять много времени, пока не будет обработана следующая макрозагрузка. Это означает, что в вашем приложении может быть заблокирован пользовательский интерфейс или какой-то завершенный ввод-вывод ввода-вывода.
Однако, по крайней мере, в отношении функции Node.js process.nextTick(которая ставит в очередь микротаксы), есть встроенная защита от такой блокировки с помощью process.maxTickDepth. Это значение установлено на значение по умолчанию 1000, сокращая дальнейшую обработку микротоков после достижения этого предела, который позволяет обрабатывать следующую макросаку)
Итак, когда использовать что?
В принципе, используйте microtasks, когда вам нужно делать асинхронно синхронно (т.е. когда вы скажете выполнить эту (микро-) задачу в ближайшем будущем).
В противном случае придерживайтесь макросов .
Примеры
макросамы: setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, рендеринг пользовательского интерфейса
microtasks: process.nextTick, Promises, Object.observe, MutationObserver
Ответ 2
Я написал сообщение об этом, включая интерактивные примеры https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
Обновление: я также рассказал об этом https://www.youtube.com/watch?v=cCOL7MC4Pl0. Обсуждение более подробно, в том числе о том, как задачи и микротовары взаимодействуют с рендерингом.
Ответ 3
Основные понятия в spec:
- Цикл событий имеет одну или несколько очередей задач (очередь задач - очередь макрозадачей)
- Каждый цикл событий имеет очередь микрозадачей.
- task queue = macrotask queue!= очередь микрозадачей
- задача может быть перенесена в очередь макрозаданных или очередь микрозадачей
- когда задача переводится в очередь (микро/макрос), мы подразумеваем, что готовящая работа завершена, поэтому задача может быть выполнена сейчас.
И модель процесса цикла событий выглядит следующим образом:
когда стек вызовов пуст, выполните шаги -
- выберите старую задачу (задачу A) в очередях задач
- если задача A равна null (значит, очереди задач пусты), перейдите к шагу 6
- установите "текущая выполняемая задача" в "task A"
- запустите "задачу А" (означает выполнение функции обратного вызова)
- установите "текущая выполняемая задача" на null, удалите "task A"
- выполнить очередь микрозадачей
- (a). выберите самую старую задачу (задачу x) в очереди микрозадачей
- (b).if задача x равна нулю (означает, что очереди микротомов пусты), перейдите к шагу (g)
- (c).set "текущая выполняемая задача" в "task x"
- (d).run "task x"
- (e).set "текущая выполняемая задача" для null, удалить "task x"
- (f). выберите следующую старую задачу в очереди микрозадач, перейдите к шагу (b)
- (g). завершить очередь микрозадачей;
- перейдите к шагу 1.
упрощенная модель процесса выглядит следующим образом:
- запустите старую задачу в очереди макроса, затем удалите ее.
- запустите все доступные задачи в очереди микрозадачей, затем удалите их.
- следующий раунд: запустить следующую задачу в очереди макрозадачей (шаг перехода 2)
что-то запомнить:
- когда выполняется задача (в очереди макрозаданных), могут регистрироваться новые события. Таким образом могут быть созданы новые задачи. Ниже приведены две новые созданные задачи:
- promA.then() обратный вызов - задача
- promA разрешено/отклонено: задача будет перенесена в очередь микрозадач в текущем раунде цикла событий.
- expectedA ожидает: задача будет перенесена в очередь микрозадач в следующем раунде цикла события (может быть следующий раунд)
- setTimeout (обратный вызов, n) обратный вызов является задачей и будет перенесен в очередь макрозаданных, даже n равно 0;
Задача - в очереди микрозадачей будет выполняться в текущем раунде, тогда как задача в очереди макрозадачей должна ждать следующего цикла цикла событий.
- Мы все знаем обратный вызов "click", "scroll", "ajax", "setTimeout"... являются задачами, однако мы также должны помнить, что js-коды в целом в теге script - задача (макрозадача ) тоже.