web-dev-qa-db-ja.com

イベントループコンテキスト内のマイクロタスクとマクロタスクの違い

Promises/A +仕様の読み終えたばかりで、マイクロタスクとマクロタスクという用語につまずいた: http://promisesaplus.com/#notes を参照

これらの用語を聞いたことはありませんが、今では違いがどうなるのか興味がありますか?

私はすでにウェブ上でいくつかの情報を見つけようとしましたが、私が見つけたのはw3.orgアーカイブからのこの投稿です(私には違いを説明していません): http://lists.w3 .org/Archives/Public/public-nextweb/2013Jul/0018.html

さらに、「マクロタスク」と呼ばれるnpmモジュールを見つけました。 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仕様を考えると、理論的には自分で違いを抽出できるはずです。しかし、専門家による短い説明があれば、他の人も同様に利益を得ることができると確信しています。

112
NicBright

イベントループの1つのゴーアラウンドには、exactly oneから処理されるタスクがあります[macrotask queue(このキューはtask queueWHATWG仕様 )。このマクロタスクが終了すると、利用可能なすべてのmicrotasksが、つまり同じゴーアラウンドサイクル内で処理されます。これらのマイクロタスクは処理されますが、さらに多くのマイクロタスクをキューに入れることができ、それらはすべてマイクロタスクキューが使い果たされるまで1つずつ実行されます。

これの実際的な結果は何ですか?

microtaskが他のマイクロタスクを再帰的にキューに入れる場合、次のマクロタスクが処理されるまでに時間がかかる場合があります。つまり、UIがブロックされたり、アプリケーションでI/Oアイドリングが完了したりする可能性があります。

ただし、少なくともNode.jsのprocess.nextTick関数([マイクロタスク)をキューに入れる)に関しては、process.maxTickDepthによるこのようなブロッキングに対する組み込みの保護があります。この値はデフォルトの1000に設定され、この制限に達した後、次のマクロタスクの処理を許可するマイクロタスクのさらなる処理を削減します)

それで、いつ何を使うのですか?

基本的に、microtasksを同期的に非同期的に行う必要がある場合(つまり、この(マイクロ)タスクを最も近い将来に実行する場合)。それ以外の場合は、マクロタスクに固執します。

マクロタスク: setTimeout、setInterval、setImmediate、requestAnimationFrame、I/O、UIレンダリング
マイクロタスク: process.nextTick、Promises、Object.observe、MutationObserver

174
NicBright

インタラクティブな例を含むこの投稿を書きました https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

更新:これについても講演しました https://www.youtube.com/watch?v=cCOL7MC4Pl 。トークでは、タスクとマイクロタスクがレンダリングとどのように相互作用するかなど、より詳細に説明します。

72
JaffaTheCake

spec の基本概念:

  • イベントループには1つ以上のタスクキューがあります(タスクキューはマクロタスクキューです)。
  • 各イベントループには、マイクロタスクキューがあります。
  • タスクキュー=マクロタスクキュー!=マイクロタスクキュー
  • タスクは、マクロタスクキューまたはマイクロタスクキューにプッシュできます。
  • タスクがキュー(マイクロ/マクロ)にプッシュされると、作業の準備が完了したことを意味するため、タスクをすぐに実行できます。

また、イベントループプロセスモデルは次のとおりです。

呼び出しスタック が空の場合、手順を実行します-

  1. タスクキュー内の最も古いタスク(タスクA)を選択する
  2. タスクAがnull(タスクキューが空であることを意味する)の場合、手順6にジャンプします。
  3. 「現在実行中のタスク」を「タスクA」に設定する
  4. 「タスクA」の実行(コールバック関数の実行を意味します)
  5. 「現在実行中のタスク」をnullに設定し、「タスクA」を削除する
  6. マイクロタスクキューを実行します
    • (a)。マイクロタスクキュー内の最も古いタスク(タスクx)を選択します。
    • (b)。タスクxがnull(マイクロタスクキューが空であることを意味する)の場合、ステップ(g)にジャンプ
    • (c)。「現在実行中のタスク」を「タスクx」に設定
    • (d).run "task x"
    • (e)。「現在実行中のタスク」をnullに設定し、「タスクx」を削除する
    • (f)。マイクロタスクキューで次に古いタスクを選択し、ステップ(b)にジャンプします。
    • (g).finishマイクロタスクキュー;
  7. ステップ1にジャンプします。

簡略化されたプロセスモデルは次のとおりです。

  1. マクロタスクキューで最も古いタスクを実行してから削除します。
  2. マイクロタスクキューで使用可能なすべてのタスクを実行し、それらを削除します。
  3. 次のラウンド:マクロタスクキューで次のタスクを実行します(ステップ2にジャンプ)

覚えておくべきこと:

  1. (マクロタスクキュー内の)タスクが実行されている場合、新しいイベントが登録される場合があります。したがって、新しいタスクが作成される場合があります。以下に2つの新しいタスクが作成されます。
    • promiseA.then()のコールバックはタスクです
      • promiseAは解決/拒否されます:taskタスクは、イベントループの現在のラウンドでマイクロタスクキューにプッシュされます。
      • promiseAは保留中です。タスクは、イベントループの次のラウンドでマイクロタスクキューにプッシュされます(次のラウンドになる可能性があります)
    • setTimeout(callback、n)のコールバックはタスクであり、nが0であってもマクロタスクキューにプッシュされます。
  2. マイクロタスクキューのタスクは現在のラウンドで実行され、マクロタスクキューのタスクはイベントループの次のラウンドを待機する必要があります。
  3. 「click」、「scroll」、「ajax」、「setTimeout」...のコールバックはタスクであることがわかっていますが、スクリプトタグ内のjsコード全体もタスク(マクロタスク)であることに注意してください。
40
wengeezhang