LoginSignup
1
1

More than 1 year has passed since last update.

【JavaScript】非同期処理⑥ マクロタスクとマイクロタスク

Posted at

はじめに

Udemyの【JS】ガチで学びたい人のためのJavaScriptメカニズムの講座の振り返りです。

前回の記事

目的

  • 非同期処理についての理解を深める

本題

1.マクロタスクとマイクロタスク

マクロタスク

  • マクロタスクはタスクキューと呼ばれていたもの
  • イベントループで処理が回ってきたら、1つずつ格納されているタスクを実行する
  • ex. setTimeout

マイクロタスク

  • マイクロタスクはタスクキューとは別に存在する非同期処理待ちの行列(ジョブキュー)
  • マイクロタスクとマクロタスクが同じイベントループで処理が行われた場合マイクロタスクが優先される
  • イベントループで処理が回ってきたら、全ての格納されているジョブを実行する
  • ex. Promise

例1

コードで確認

// マクロタスク
// タスクの待機時間はなし
setTimeout(function task1() {
  console.log('task1');
});

// マイクロタスク
new Promise(function promise(resolve) {
  console.log('promise');
  resolve();
}).then(function job1() {
  console.log('job1');
});

// グローバルコンテキスト
console.log('global end');

// 実行結果は以下の通り
// Promise
// global end
// job1
// task1

ひとつひとつ確認すると

// 非同期処理でタスクキューで処理される
// グローバルコンテキストが呼ばれた後に実行される
setTimeout(function task1() {
  console.log('task1');
});

new Promise(function promise(resolve) {
  // ここは同期的に処理される
  // だから一番最初に表示される
  console.log('promise');
  resolve();
}).then(function job1() {
  // ここも非同期処理なのでグローバルコンテキスト実行後
  // マイクロタスクが先に処理されるのでこちらが先に出力される
  console.log('job1');
});

// 先の同期処理"promise"後表示
console.log('global end');

例2

マクロタスクとマイクロタスクが絡み合った際にどのような処理になるのか

1. マイクロタスクの中にマクロタスクがある状態

new Promise(function promise(resolve) {
  // まず一番最初は同期的に実行される`promise`
  console.log('promise');
  // マクロタスクだがthenメソッドはresolveの実行を待つので3番目に下記が実行される
  setTimeout(function task1() {
    console.log('task1');
    resolve();
  });
// resolve実行された時に4番目に下記が出力される
}).then(function job1() {
  console.log('job1');
})

// 次の同期処理である下記が2番目に出力
console.log('global end')

// 実行順序は以下の通りとなる
// promise
// global end
// task1
// job1

2. job2, job3を追加し、job1の後にsetTimeoutを追加する

new Promise(function promise(resolve) {
  console.log('promise');

  setTimeout(function task1() {
    console.log('task1');
    resolve();
  });

  // resolve実行後先にjob1を実行
  // マイクロタスクは格納されている全てのジョブを実行する
  // よってjob2,job3も実行する
}).then(function job1() {
  console.log('job1');
  setTimeout(function task2() {
    // マイクロタスク実行後にマクロタスクtask2を実行する
    console.log('task2');
  });
}).then(function job2() {
  console.log('job2');
}).then(function job3() {
  console.log('job3');
})

console.log('global end');

// 実行順序は以下の通りとなる
// promise
// global end
// task1
// job1
// job2
// job3
// task2

3. 関数queueMicrotaskを呼んでみた場合(job4の実行)

new Promise(function promise(resolve) {
  console.log('promise');

  setTimeout(function task1() {
    console.log('task1');
    resolve();
  });

}).then(function job1() {
  console.log('job1');
  setTimeout(function task2() {
    console.log('task2');
  });
  // thenメソッドが呼ばれた際にjob4が発見されるので、job2,3よりも先に実行される
  queueMicrotask(function job4(){
    console.log("job4");
  });

}).then(function job2() {
  console.log('job2');
}).then(function job3() {
  console.log('job3');
})

console.log('global end');

// 実行順序は以下の通りとなる
// promise
// global end
// task1
// job1
// job4  ← ここで実行されてる
// job2
// job3
// task2

4. setTimeoutの中にqueueMicrotaskを入れてみる

new Promise(function promise(resolve) {
  console.log('promise');

  setTimeout(function task1() {
    console.log('task1');
    resolve();
  });

}).then(function job1() {
  console.log('job1');
  setTimeout(function task2() {
    console.log('task2');
    // 先にresolveを実行し、job1~3まで実行
    // setTimeoutの関数に従うのでtask2実行後にjob4を実行する
    queueMicrotask(function job4(){
      console.log("job4");
    });
  });

}).then(function job2() {
  console.log('job2');
}).then(function job3() {
  console.log('job3');
})

console.log('global end');

// 実行順序は以下の通りとなる
// promise
// global end
// task1
// job1
// job2
// job3
// task2
// job4  ← ここで実行されてる

5. queueMicrotaskをPromiseで書き換える

new Promise(function promise(resolve) {
  console.log('promise');

  setTimeout(function task1() {
    console.log('task1');
    resolve();
  });

}).then(function job1() {
  console.log('job1');
  setTimeout(function task2() {
    console.log('task2');
    // queueMicrotaskの書き換え
    const p = Promise.resolve();
    p.then(function job4() {
      console.log("job4")
    })
  });

}).then(function job2() {
  console.log('job2');
}).then(function job3() {
  console.log('job3');
})

console.log('global end');

// 実行順序は以下の通りとなる
// promise
// global end
// task1
// job1
// job2
// job3
// task2
// job4  ← ここで実行されてる

今日はここまで!

参考にさせて頂いた記事

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1