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

Я только что закончил читать спецификацию 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

Ответ 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 - задача (макрозадача ) тоже.