JS事件循环机制(event loop),什么是宏任务、微任务

JavaScript 这门语言跟其他语言有区别,如果你看Jquery,Vue,React,Angular源码的时候,如果你没有理解事件机制很难理解里面的一些内容。

JAVA ,Python是多线程语言(Python可是说是伪多线程)代码的写法跟JavaScript有太大的区别了,写惯多线程语言的代码,写JavaScript要有一定的适应期。

现在HTML5,ES6,ES7,ES8,ES9有很大的改进很多时候不用写这种回调的代码了JavaScript有点像Python了现在。

先不要理什么是任务,看一段代码;

for(var i=0;i<5;i++ ){
setTimeout(function(){
console.log(i)
},0)
}
// 请问打印出是什么
答案 5

js 是就是这么奇葩,每个前端开发者都会被这个异步回调搞的头晕脑胀。

下面这段代码打印顺序是什么呢?

console.log('start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('end');
JS事件循环机制(event loop),什么是宏任务、微任务

答案是:

  1. start
  2. end
  3. promise1
  4. promise2
  5. setTimeout

其实有些浏览器是不支持Promise 答案会有所不同。但是那些不是本篇文章考虑的内容。

为什么会出现这样的顺序呢?

要想知道为啥会这样那就要理解JavaScript的宏任务和微任务。

js执行的时候也就是每个线程(不知道没有关系)都有一个事件队列,这个事件队列是等所有的主线程执行(原代码的顺序)完成后,再执行事件队列执行的走的是事件循环,而且遵循事件循环。

这些宏任务源保证了在本任务源内的顺序。但是浏览器每次都会选择一个源中的一个宏任务去执行。这保证了浏览器给与一些宏任务(如用户输入)以更高的优先级。好的,跟着我继续……

宏任务(task)

浏览器为了能够使得JS内部task与DOM任务能够有序的执行,会在一个task执行结束后,在下一个 task 执行开始前,对页面进行重新渲染 (task->渲染->task->...)

在上面的例子中:

setTimeout的作用是等待给定的时间后为它的回调产生一个新的宏任务。

这就是为什么打印‘setTimeout’在‘end’之后,即使setTimeout代码再‘end’前面。因为打印‘end’是第一个宏任务里面的事情,setTimeout它的回调产生一个新的宏任务,所以会在下一个事件循环的时候执行,即使是为0秒也是在‘end’之后执行promise1,promise2,在下一个

微任务(Microtasks )

微任务是在当前宏任务 task 执行结束后立即执行的任务。

需要异步的执行任务而又不需要分配一个新的宏任务 task

这样便可以减小一点性能的开销。

只要执行栈中没有其他的js代码正在执行且每个宏任务执行完,微任务队列会立即执行。

微任务包括了mutation observe的回调还有接下来的例子promise的回调。

知道了宏任务 (task)和微任务(Microtasks ),再来分析上面的代码。

代码执行的时候这个时候是第一个宏任务(task),执行 start ,setTimeout生成另外一个宏任务,也就代码挂起来了等下个事件循环的时候执行。执行Promise的时候是一个微任务,所以是等到当前宏任务执行完在走,所以执行 end 再执行微任务promise1,promise2。这个时候第一个宏任务执行完毕,第二个宏任务开始执行setTimeout。

翻译原文:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/?utm_source=html5weekly

这篇文章希望能帮助到各位同学。


分享到:


相關文章: