Разница между microtask и macrotask в контексте цикла событий

Я только что закончил читать спецификацию 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. Но я уверен, что другие также могли бы извлечь выгоду из короткого объяснения, данного экспертом.

3 ответов


один обход цикла событий будет иметь ровно задача обрабатывается из очереди macrotask (эта очередь просто называют задач очередь на спецификация WHATWG). После завершения этой макротаски все доступные microtasks будет обработано, а именно в рамках того же цикла обхода. Пока эти микротаски обрабатываются, они могут стоять в очереди еще больше микротасков, которые будут выполняться по одному, пока очереди microtask исчерпан.

каковы практические последствия этого?

Если microtask рекурсивно очереди другие microtasks, это может занять много времени до следующего macrotask обработки. Это означает, что вы можете в конечном итоге с заблокированным пользовательским интерфейсом, или некоторые законченные ввода/вывода холостого хода в приложении.

однако, по крайней мере, относительно узла.процесс js.функция nextTick (которая queues microtasks), есть встроенный защита от такой блокировки с помощью процесса.maxTickDepth. Это значение по умолчанию равно 1000, что сокращает дальнейшую обработку microtasks после достижения этого предела, который позволяет следующий macrotask для обработки)

так когда использовать что?

в принципе, использовать microtasks когда вам нужно делать вещи асинхронно синхронно (т. е. когда вы скажете выполните эту (микро-)задачу в большинстве ближайшее будущее). В противном случае придерживайтесь macrotasks.

примеры

macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, ввод / вывод, рендеринг пользовательского интерфейса
microtasks:


Я написал сообщение об этом, включая интерактивные примеры https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

Update: я также говорил об этомhttps://www.youtube.com/watch?v=cCOL7MC4Pl0. Разговор идет более подробно, в том числе о том, как задачи и микротаски взаимодействуют с рендерингом.


Основные понятия spec:

  • цикл обработки событий имеет одну или несколько очередей задач.(очередь заданий очередь macrotask)
  • каждый цикл событий имеет очередь микрозадач.
  • очередь задач = очередь макротасков != очереди microtask
  • задача может быть толкнул в очереди macrotask,или очереди microtask
  • когда задача помещается в очередь (микро / макрос), мы имеем в виду,что подготовка работы завершена, поэтому задача может быть выполнена сейчас.

и модель процесса цикла событий выглядит следующим образом:

, когда стек вызовов пусто, выполните шаги -

  1. выберите самую старую задачу (задача A) в очередях задач
  2. если задача A равна null(означает, что очереди задач пусты), перейдите к шагу 6
  3. установите "текущая задача" в "Задача A"
  4. выполнить "задачу A"(означает запустить функцию обратного вызова)
  5. набор "запущенные задачи" на null,удалить "задач А"
  6. выполнить очереди microtask
    • (a).выберите самую старую задачу (задача x) в очереди микрозадач
    • (b).если задачу х является нулем(очередей microtask пуст),перейти к шагу (г)
    • (c).установите "текущая задача" в "Задача x"
    • (d).запустите "task x"
    • (e).набор "запущенные задачи" на null,удалить "задачу х"
    • (f).выберите следующую самую старую задачу в очереди микрозадач, перейдите к шагу (b)
    • (g).отделка microtask очередь;
  7. перейти к шагу 1.

упрощенная модель процесса выглядит следующим образом:

  1. запустите самую старую задачу в очереди macrotask, затем удалите ее.
  2. запустите все доступные задачи в очереди microtask,затем удалите их.
  3. следующий раунд: запустите следующую задачу в очереди макротасков (шаг перехода 2)

что-то помню:

  1. когда задача (в очереди макротасков) выполняется, новые события могут быть зарегистрирован.Поэтому могут быть созданы новые задачи.Ниже приведены две новые созданные задачи:
    • обещали.тогда обратный вызов () - это задача
      • promiseA разрешен / отклонен: задача будет помещена в очередь микрозадач в текущем цикле событий.
      • promiseA в ожидании: задача будет помещена в очередь микрозадач в будущем раунде цикла событий (может быть следующий раунд)
    • setTimeout (callback,n) обратный вызов является задачей и будет нажата в очередь макротасков, даже n равно 0;
  2. задача в очереди microtask будет запущена в текущем раунде, в то время как задача в очереди macrotask должна ждать следующего цикла событий.
  3. мы все знаем обратный вызов "click","scroll","ajax", "setTimeout"... являются задачами, однако мы также должны помнить, что JS-коды в целом в теге скрипта также являются задачей(макротаской).