JavaScript Academy · レッスン

マイクロタスクと Promise

Promise のコールバックが先に実行される理由を学びます。

レッスン 3/413 ステップ

「マイクロタスクと Promise」はCoddyKit上の無料JavaScript Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJavaScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 JavaScript Academyコースには全4レッスンが含まれています。

マイクロタスクとは

マイクロタスクとは、優先度の高い遅延実行ジョブです。Promise のコールバック(.then、.catch、.finally)と queueMicrotask は、いずれもマイクロタスクをスケジュールします。

重要なルールは、同期処理が終わるたびに、どのマクロタスクよりも先にすべてのマイクロタスクが処理されることです。

Promise のコールバックは遅延実行される

すでに解決済みの Promise であっても、.then コールバックはマイクロタスクとしてスケジュールされます。同期的には実行されません。

console.log('start');
Promise.resolve().then(() => console.log('promise then'));
console.log('end');

マイクロタスクはマクロタスクより先に実行される

これは最も重要な実行順序のルールです。タイマーが先にスケジュールされていても、Promise のコールバックは setTimeout のコールバックより先に実行されます。

setTimeout(() => console.log('timeout (macro)'), 0);
Promise.resolve().then(() => console.log('promise (micro)'));
console.log('sync');

マイクロタスクキューは完全に処理される

イベントループは、次のマクロタスクを取り出す前に、マイクロタスクキュー全体を空にします。複数の Promise コールバックは、この処理中にまとめて実行されます。

setTimeout(() => console.log('macro'), 0);
Promise.resolve().then(() => console.log('micro 1'));
Promise.resolve().then(() => console.log('micro 2'));
console.log('sync');

Promise のチェーン

チェーン内の各 .then は、直前の処理が完了すると新しいマイクロタスクをスケジュールします。それらは保留中のタイマーよりも先にすべて実行されます。

setTimeout(() => console.log('timeout'), 0);
Promise.resolve()
  .then(() => console.log('then 1'))
  .then(() => console.log('then 2'))
  .then(() => console.log('then 3'));
console.log('sync');

処理中にスケジュールされたマイクロタスク

マイクロタスクが別のマイクロタスクをスケジュールすると、新しいマイクロタスクも同じ処理中に、マクロタスクより先に実行されます。キューが本当に空になるまで、処理は続きます。

Promise.resolve().then(() => {
  console.log('micro A');
  Promise.resolve().then(() => console.log('micro B (added later)'));
});
setTimeout(() => console.log('macro'), 0);
console.log('sync');

解決された値は次へ渡される

.then ハンドラーから返された値は、すべてマイクロタスクを介して、チェーン内の次のハンドラーへの入力になります。

Promise.resolve(2)
  .then(n => n * 3)
  .then(n => n + 1)
  .then(n => console.log('result', n));
console.log('sync first');

async/await はマイクロタスクを使用する

await の後にあるコードは、マイクロタスクとして再開されます。そのため、待機後の処理は、先にスケジュールされたタイマーよりも前に実行されます。

async function run() {
  console.log('a');
  await null;
  console.log('c (after await)');
}
setTimeout(() => console.log('d (timeout)'), 0);
run();
console.log('b');

実行順序を組み合わせた例

ここまでの内容をすべて組み合わせます。実行順序を予測してみましょう。最初に同期処理、次にすべてのマイクロタスク、最後にマクロタスクです。

console.log('1 sync');
setTimeout(() => console.log('5 timeout'), 0);
Promise.resolve().then(() => console.log('3 promise'));
Promise.resolve().then(() => console.log('4 promise'));
console.log('2 sync');

マイクロタスクの飢餓状態が危険な理由

マイクロタスクは常にマクロタスクより先に実行されるため、マイクロタスクを無限にスケジュールし続けるマイクロタスクは、タイマーやレンダリングを妨げる可能性があります。マイクロタスクのチェーンは有限にしてください。

let n = 0;
function loop() {
  if (n++ < 3) {
    console.log('micro ' + n);
    Promise.resolve().then(loop);
  }
}
setTimeout(() => console.log('macro after micros'), 0);
loop();

この実行順序が重要な理由

マイクロタスクがマクロタスクより先に実行されることを知っていれば、Promise の結果がタイマーのコールバックより先に現れる理由や、実行順序のバグが起きる理由を説明できます。ルールは単純です。同期処理、すべてのマイクロタスクの処理、1つのマクロタスク、そして繰り返しです。

console.log('A');
Promise.resolve().then(() => console.log('B'));
setTimeout(() => console.log('D'), 0);
console.log('C');

クイックチェック

Promise の .then と setTimeout(fn, 0) がどちらも保留中です。どちらが先に実行されますか。

まとめ: マイクロタスクと Promise

次の優先順位のルールを学びました。

  • マイクロタスクは Promise と queueMicrotask によって作成されます。
  • マクロタスクより先に、マイクロタスクキュー全体が処理されます。
  • async/await の待機後の処理はマイクロタスクです。
  • 終わりのないマイクロタスクのチェーンは、タイマーやレンダリングを妨げる可能性があります。
無料で開始

AI チューターと学ぶ JavaScript — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
59
レッスン
200

よくある質問

「マイクロタスクと Promise」レッスンは無料ですか?

はい。「マイクロタスクと Promise」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、JavaScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 JavaScript Academyコースには全4レッスンが含まれています。

「マイクロタスクと Promise」で何を学びますか?

Promise のコールバックが先に実行される理由を学びます。 ブラウザで直接実行するハンズオンコードでJavaScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

JavaScript Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJavaScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「マイクロタスクと Promise」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJavaScript Academyレッスンでコードを書いて実行できますか?

はい。すべてのJavaScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. コールスタック
  2. マクロタスクとタスクキュー
  3. マイクロタスクと Promise
  4. queueMicrotask と実行順序
← JavaScript Academyに戻る