BLOG

非同期処理メモ⑪(マイクロさんマクロさん続き)

おはようございます。

最近の楽しみは仕事の日はお昼ごはんを外に食べに行くこと、どうもハヤトワンです。

コロナで引きこもってた分の外食を今爆速で取り戻しちゃっています。←

はい、今日も非同期処理のマクロタスク、マイクロタスクについてのメモメモ_φ(・_・

▼まずこんなコードを書いてみる

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

  setTimeout(function task1() {
    console.log('タスク1');
    resolve();
  });
}).then(function job1(){
  console.log('ジョブ1')
}).then(function job2(){
  console.log('ジョブ2')
}).then(function job3(){
  console.log('ジョブ3')
});

console.log('global end');

コンソール

promise
global end
タスク1
ジョブ1
ジョブ2
ジョブ3

▼これにsetTimeoutを追加してみるとどうなるか

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

  setTimeout(function task1() {
    console.log('タスク1');
    resolve();
  });
}).then(function job1(){
  console.log('ジョブ1')
  setTimeout(function task1(){
    console.log('タスク2');
  })
}).then(function job2(){
  console.log('ジョブ2')
}).then(function job3(){
  console.log('ジョブ3')
});

console.log('global end');

コンソール

promise
global end
タスク1
ジョブ1
ジョブ2
ジョブ3
タスク2

このようになる。

この場合、マイクロタスク実行中にマクロタスクを追加しているため、(setTimeout)、ジョブ2、ジョブ3のマイクロタスクが全て完了した後に、マクロタスクであるタスク2が実行されることになる。

▼次にマイクロタスクにキューをつめる、queueMicrotaskという関数を呼んでみるとこうなる。

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

  setTimeout(function task1() {
    console.log('タスク1');
    resolve();
  });
}).then(function job1(){
  console.log('ジョブ1')
  setTimeout(function task1(){
    console.log('タスク2');
  })

  queueMicrotask(function job4(){
    console.log('ジョブ4')
  })

}).then(function job2(){
  console.log('ジョブ2')
}).then(function job3(){
  console.log('ジョブ3')
});

console.log('global end');

コンソール

promise
global end
タスク1
ジョブ1
ジョブ4
ジョブ2
ジョブ3
タスク2

するとこのように、ジョブ1の後にジョブ4が呼ばれている。

▼次にこのqueueMicrotaskをsetTimeoutの中にいれてみる

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

  setTimeout(function task1() {
    console.log('タスク1');
    resolve();
  });
}).then(function job1(){
  console.log('ジョブ1')
  setTimeout(function task1(){
    console.log('タスク2');

    queueMicrotask(function job4(){
      console.log('ジョブ4')
    })
  })



}).then(function job2(){
  console.log('ジョブ2')
}).then(function job3(){
  console.log('ジョブ3')
});

console.log('global end');

コンソール

promise
global end
タスク1
ジョブ1
ジョブ2
ジョブ3
タスク2
ジョブ4

すると、タスク2の後にジョブ4が呼ばれる。

そしてこのようにsetTimeoutを上にもってきたとする。

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

  setTimeout(function task1() {
    console.log('タスク1');
    resolve();
  });

  setTimeout(function task1(){
    console.log('タスク2');

    queueMicrotask(function job4(){
      console.log('ジョブ4')
    })
  })
  
}).then(function job1(){
  console.log('ジョブ1')




}).then(function job2(){
  console.log('ジョブ2')
}).then(function job3(){
  console.log('ジョブ3')
});

console.log('global end');

コンソール

promise
global end
タスク1
ジョブ1
ジョブ2
ジョブ3
タスク2
ジョブ4

そうしても順番は変わらない。

この場合でもsetTimeoutはマクロタスクになるので、一度マイクロタスクの実行が始まると、それ以降はマイクロタスクがはけるまではジョブを順々に実行することになる。

そして溜まっているジョブが全てはけた後にマクロタスクの実行に移る。(setTimeout)

このようにマクロタスクは1つずつ、マイクロタスクは溜まっているジョブ全てを実行するという風に覚えておく。

▼queueMicrotaskはPromiseを使っても書き換えれる。

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

  setTimeout(function task1() {
    console.log('タスク1');
    resolve();
  });

  setTimeout(function task1(){
    console.log('タスク2');

    const p = Promise.resolve();
    p.then(function job4(){
      console.log('ジョブ4p')
    })

    queueMicrotask(function job4(){
      console.log('ジョブ4')
    })
  })

}).then(function job1(){
  console.log('ジョブ1')




}).then(function job2(){
  console.log('ジョブ2')
}).then(function job3(){
  console.log('ジョブ3')
});

console.log('global end');

コンソール

promise
global end
タスク1
ジョブ1
ジョブ2
ジョブ3
タスク2
ジョブ4p
ジョブ4

このようにすると、実質的にマイクロタスクに処理をつめるためのqueueMicrotaskと同じ動きになる。

このようなコードを見かけたら、グローバルコンテキストが実行された後に処理したい非同期処理という風に考える。

なるほどなるほど、

繰り返して学ぶと少しずつ分かってきた気がする。

ということで、今日はここまで。

今日も良い1日を!