探索浏览器中的事件循环 Event loop

前言:由于浏览器中的事件循环机制与nodeJS中的事件循环机制不同,本文只记录基于浏览器的事件循环,希望能帮助到大家。

什么是异步?

我们知道 javascript 由于要和浏览器进行交互,所以从一开始它就被设计成了一门单线程非阻塞的脚本语言,

所谓单线程:即是任何时候,都只有一个主线程来处理所有的逻辑任务。
所谓非阻塞:即主线程不会直接处理异步任务,而是当它们返回结果之后再去处理,因为异步操作往往具有不确定性,会阻塞浏览器的渲染。
我们常用的,例如 ajax 请求、setTimeout、promise 都是异步操作

浏览器中的事件循环 event loop

html 标准中定义:

为了协调事件(event),用户交互(user interaction),脚本(script),渲染(rendering),网络(networking)等,用户代理(user agent)必须使用事件循环(event loops)。
有两类事件循环:一种针对浏览上下文(browsing context),还有一种针对worker(web worker)。

执行栈和事件队列

1.执行栈:

因为js是单线程的,同一时间只能执行一个方法,于是这些方法被排队在一个单独的地方。这个地方被称为执行栈。

chrome浏览器Developer Tools 中的 performance 中的火焰图展示的便是执行栈的过程。
这里写图片描述

2.事件队列:

事件队列主要有宏任务队列和微任务队列

异步事件会由异步处理模块进行处理,返回处理结果后,加入与当前执行栈不同的其他队列

3.宏任务(task/macrotask):

可以有一个或多个 task 队列

script(全局任务,每一个js文件也是一个宏任务), setTimeout, setInterval, I/O, UI rendering.,setImmediate(属于nodeJS )。

4.微任务(microtask):

只有一个 microtask 队列

Promise, Object.observer, MutationObserver,process.nextTick(属于 nodeJS )。

事件循环执行顺序

1. event loop 执行步骤:
  • 1、执行宏任务(先进先出),一次循环只执行一个宏任务)
  • 2、执行栈 —— 同步方法顺序执行,异步方法交给异步处理模块
  • 3、执行栈为空时取出微任务执行(先进先出),直到微任务队列为空
  • 4、更新UI渲染。完成一轮循环,反复执行1-4。(不一定每次循环都会渲染)
2.update the rendering 渲染更新:
  • 在一轮event loop中多次修改同一dom,只有最后一次会进行绘制。
  • 渲染更新(Update the rendering)会在event loop中的tasks和microtasks完成后进行,但并不是每轮event loop都会更新渲染,浏览器有自己的机制来确定是否要更新渲染。如果在一帧(16.7ms)里多次修改了dom,浏览器可能只会渲染绘制一次。
  • 如果希望在每轮event loop都即时呈现变动,可以使用requestAnimationFrame.

巩固练习

1.简单测试:
setTimeout(
    function(){
        console.log('1')
},0);

new Promise(
    function(resolve){
        console.log('2');
        resolve()
}).then(
    function(){
        console.log('3');
});

console.log('4');

打印结果:

2
4
3
1

注意:
Promise 自身的代码是同步执行的,只有 .then后的回调函数才是微任务。
主线程的执行过程:
1、从宏任务队列(task)中取出 script,将所有同步代码推入执行栈中执行,遇到异步代码交给异步处理模块,异步处理模块处理完成后将任务按规则推入事件队列,宏任务推宏任务队列(先进先出),微任务推微任务队列(先进先出)。 所以输出 2 和 4
2、执行完 script 中的同步代码,再将微任务队列中最老的任务推入执行栈执行,直到清空微任务队列。 所以输出 3
3、浏览器更新渲染,再去宏任务队列中取出最老的任务推入执行栈中执行,循环以上步骤。 所以输出 1
2.进阶摸索

自己多写一些例子来练习。
这里有一篇非常好的英文的文章推荐给大家,有个交互演示非常直观明了
Tasks, microtasks, queues and schedules
还有一篇中文的文章,也有交互演示。
深入理解 JavaScript 事件循环(一)— event loop

3.深入探索

为什么setTimeout的执行时间并不够精确?
思考宏任务队列为什么可以有多个,而微任务队列只有一个?
深入探索 chrome dev Tools 的 performance。
nodeJS中的事件循环又是怎么实现的?

结语

有误请指正,希望共同进步。


参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值