事件循环-阅读笔记

128 阅读2分钟

Tasks, microtasks, queues and schedules - JakeArchibald.com

每个线程都有自己的事件循环,
每个web woker都有自己的事件循环,所以他可以独立循环,
同一个origin的所有窗口共享一个事件循环,所以他们可以同步通信。

Microtask 微任务

微任务通常被安排用于在当前执行脚本之后立即发生的事情,比如对操作做出反应,或者用于异步。
微任务队列在每次任务结束(栈清空)时处理。
在处理微任务期间,所有微任务都会被处理,直到清空。
微任务包括:nextTick,mutation observer callbacks,promise callbacks

nextTick优先级高于其他微任务,先执行完所有nextTick(),才执行其他微任务

  • Task 按顺序执行,浏览器可以在任务之间进行渲染。
  • Microtask 按顺序执行:
    • 在每次回调之后,没有其他 JavaScript 处于中间执行状态的时候。
    • 在每个Task任务结束时

示例1

console.log('script start');

setTimeout(function () {
  console.log('setTimeout');
}, 0);

Promise.resolve()
  .then(function () {
    console.log('promise1');
  })
  .then(function () {
    console.log('promise2');
  });

console.log('script end');

结果:
script start
script end
promise1
promise2
setTimeout

示例2: 点击inner

<div class="outer">
  <div class="inner"></div>
</div>
// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');

// Let's listen for attribute changes on the
// outer element
new MutationObserver(function () {
  console.log('mutate');
}).observe(outer, {
  attributes: true,
});

// Here's a click listener…
function onClick() {
  console.log('click');

  setTimeout(function () {
    console.log('timeout');
  }, 0);

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

  outer.setAttribute('data-random', Math.random());
}

// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);

点击inner后结果:
click
promise
mutate
click
promise
mutate
timeout
timeout

示例3: 在上述代码后面加入一行

inner.click();

与示例2的区别是,2是手动点击,3是js触发 输出结果:
click
click
promise
mutate
promise
timeout
timeout

其余补充

  • timers: 这个阶段执行setTimeout()setInterval()设定的回调。
  • pending callbacks: 上一轮循环中有少数的 I/O callback 会被延迟到这一轮的这一阶段执行。
  • idle, prepare: 仅内部使用。
  • poll: 执行 I/O callback,在适当的条件下会阻塞在这个阶段
  • check: 执行setImmediate()设定的回调。
  • close callbacks: 执行比如socket.on('close', ...)的回调。

每个阶段执行完毕后,都会执行所有微任务(先 nextTick,后其它),然后再进入下一个阶段。