前言

  最近在准备春招,刷到了JS中的主要运行机制--Event Loop,觉得它的实现思路有必要整理一下,以防忘记。关于它在浏览器上的实现,我结合了自己的理解以及示例代码,想用最通俗的语言表达出来。如果在文中出现书写错误的地方,欢迎大家留言一起探讨。

正文

  关于Event Loop,宏任务,微任务的概念不再此赘述了。

概念

  进入主题,我理解的浏览器的事件循环Event Loop,以及执行一个JavaScript代码的流程如下:

  1. 一开始整段脚本作为第一个宏任务执行;
  2. 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列;
  3. 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空;如果在执行微任务的过程中,又产生了微任务,那么会加入到队列的末尾,也会在这个周期被调用执行;
  4. 执行浏览器 UI 线程的渲染工作;
  5. 执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空。

代码

     console.log('start');

     setTimeout(() => {
console.log('timeout');
Promise.resolve().then(() => {
console.log('p1')
});
}); Promise.resolve().then(() => {
console.log('p2');
}); console.log('end'); new Promise((resolve, reject) => {
console.log('end2')
resolve('p3')
}).then((data) => {
console.log(data);
})
//输出结果为:

    start 
    end
    end2
    p2
    p3
    timeout
    p1

解析:

Step 1:执行全局Script代码

console.log('start');
//打印结果:start

  栈:[ console ]

  宏任务队列:[ ]

  微任务队列:[ ]

setTimeout(() => {
console.log('timeout');//将这个回调函数叫做callback1,由于setTimeout属于宏任务,所以放到宏任务队列
   Promise.resolve().then(() => {
console.log('p1')
});
}); //打印结果:start

  栈:[ setTimeout ]

  宏任务队列:[ callback1 ]

  微任务队列:[ ]

Promise.resolve().then(() => {
console.log('p2');  //将这个回调函数叫做callback2,由于Promise属于微任务,所以放到微任务队列
}); //打印结果:start

  栈:[ Promise ]

  宏任务队列:[ callback1 ]

  微任务队列:[ callback2 ]

console.log('end');

/*
打印结果:start
        end
*/

  栈:[ console ]

  宏任务队列:[ callback1 ]

  微任务队列:[ callback2 ]

 new Promise((resolve, reject) => {
console.log('end2')  //注意,这里是同步执行的!!!
resolve('p3')  //将这个回调函数叫做callback3,由于Promise属于微任务,所以放到微任务队列
}).then((data) => {
console.log(data);
}) /*
打印结果: start
         end
         end2
*/

  栈:[ Promise ]

  宏任务队列:[ callback1 ]

  微任务队列:[ callback2 callback3 ]

Step 2:全局Script代码执行完成,进入微任务队列,取出任务并执行,直至微任务队列为空。

  微任务队列:[ callback2 callback3 ]

  1.首先执行callback2任务:

Promise.resolve().then(() => {
console.log('p2');  //将这个回调函数叫做callback2
}); //打印结果:start
      end
      end2
      p2

  栈:[ callback2 ]

  宏任务队列:[ callback1 ]

  微任务队列:[ callback3 ] 

  2.其次执行callback3任务:

 new Promise((resolve, reject) => {
console.log('end2')  //注意,这里是同步执行的
resolve('p3')  //将这个回调函数叫做callback3
}).then((data) => {
console.log(data);
}) /*
打印结果:start
       end
       end2
       p2
       p3
*/

  栈:[ callback3 ]

  宏任务队列:[ callback1 ]

  微任务队列:[ ] 

Step3:微任务队列全部执行完,再去宏任务队列中取第一个任务执行。

setTimeout(() => {
console.log('timeout');  //将这个回调函数叫做callback1
   Promise.resolve().then(() => {
console.log('p1')    //将这个回调函数叫做callback4
});
});
//打印结果:start
       end
       end2
       p2
       p3
       timeout

【注】:当执行callback1的时候又遇到了另一个promise,promise异步执行完后在微任务队列中又注册了一个callback4回调函数。

  栈:[ callback1 ]

  宏任务队列:[ ]

  微任务队列:[ callback4 ] 

Step4:当前宏任务执行完出队,检查微任务队列

setTimeout(() => {
console.log('timeout');  
   Promise.resolve().then(() => {
console.log('p1')    //将这个回调函数叫做callback4
});
}); /*
打印结果:start
       end
       end2
       p2
       p3
       timeout
p1
*/

  栈:[ callback4 ]

  宏任务队列:[ ]

  微任务队列:[ ]

至此,执行完毕。

尾声

以上就是我分析的浏览器篇Event Loop的一个例子,如有错误,还请指正,谢谢!希望本次分享对你有用呀 ^_^

如何理解EventLoop--浏览器篇的更多相关文章

  1. 我是这样理解EventLoop的

    我是这样理解EventLoop的 一.前言   众所周知,在使用javascript时,经常需要考虑程序中存在异步的情况,如果对异步考虑不周,很容易在开发中出现技术错误和业务错误.作为一名合格的jav ...

  2. [Web] 深入理解现代浏览器

    转载: https://blog.csdn.net/qihoo_tech/article/details/91921777 奇技指南 身为前端,你真正深入理解了浏览器吗? 本文来自公众号奇舞周刊,作者 ...

  3. C#串口通讯教程 简化一切 只保留核心功能 这可能是最易于理解的一篇教程

    C#串口通讯教程 简化一切 只保留核心功能 这可能是最易于理解的一篇教程   串口的定义,请自行了解. C#操作串口通讯在.Net强大类库的支持下,只需要三个步骤: 1 创建 2 打开 3 发送/接受 ...

  4. 前端面试总结——http、html和浏览器篇

    1.http和https https的SSL加密是在传输层实现的. (1)http和https的基本概念 http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和 ...

  5. iOS开发:深入理解GCD 第一篇

    最近把其他书籍都放下了,主要是在研究GCD.如果是为了工作,以我以前所学的GCD.NSOperation等知识已经足够用了,但学习并不仅仅知识满足于用它,要知其然.并且知其所以然,这样才可以不断的提高 ...

  6. 15分钟理解HTTPS——通俗篇

    | 导语 它很深奥吗?你肯定常常见过它,使用它,甚至离不开它... 它很浅显吗?你可能觉得看透它,理解它,甚至懂它... 让我们用15分钟,不那么学术地将它的深挖到底~ 什么?如何证明我是我?本文要上 ...

  7. 理解 EventLoop

    链接 链接 node 浏览器 执行顺序有差异 macrotask microtask 一个线程会有 堆 栈 消息队列;  栈函数执行是用的, 堆用了存放定义的对象, 消息队列来处理异步的操作 a() ...

  8. 理解http浏览器的协商缓存和强制缓存

    阅读目录 一:浏览器缓存的作用是什么? 二:理解协商缓存 1 Last-Modified/if-Modify-Since 2 ETag/if-None-Match 三:理解强制缓存 回到顶部 一:浏览 ...

  9. Range对象理解,浏览器兼容性,获取鼠标光标位置

    一.关于浏览器的兼容性 目前主要有3种关于range的类似的对象,分别是W3C range 对象,Mozzlia selection ,ie TextRange 关于这三种的区别,请查看文档 http ...

  10. iOS开发:深入理解GCD 第二篇(dispatch_group、dispatch_barrier、基于线程安全的多读单写)

    Dispatch Group在追加到Dispatch Queue中的多个任务处理完毕之后想执行结束处理,这种需求会经常出现.如果只是使用一个Serial Dispatch Queue(串行队列)时,只 ...

随机推荐

  1. node.js-web服务器

    node.js--web服务器 目前最主流的三个Web服务器是Apache.Nginx.IIS. 使用 Node 创建 Web 服务器 以下是演示一个最基本的 HTTP 服务器架构(使用8081端口) ...

  2. 搭建Flutter开发环境需要注意的几个小Tips

    目录 下载SDK 安装 Android Stdio + SDK + tool SDK + 创建模拟器 + 插件(flutter和dart) Xcode + cocoapods VSCode + Flu ...

  3. Linux进程操作记录

    关于Gunicorn如何终止进程: 1.用进程树显示主进程PID: pstree -ap | grep gunicorn 2.如果有daemon进程无法用kill -9删除(可能是因为daemon屏蔽 ...

  4. linux使用php动态安装模块mysqli.so(ext/mysqlnd/mysqlnd.h: 没有那个文件或目录)

    由于我先安装的php,再安装的mysql! 正常过程: 1.安装mysql 2.安装php configure时带–with-mysql参数 现在我不想重装,因此使用phpize动态安装mysqli, ...

  5. 基于GIS空间分析的多边形提取技术

    现有基于矢量图形的骨架线提取方法主要包括数据预处理.基于约束 Delauny 三角剖分的骨架线结点生成和骨架线的连接 3 个过程,上述过程都可利用现有 GIS 系统的数据处理.空间分析和建模功能实现. ...

  6. 为什么你学习了scrum之后还不会实施敏捷? (敏捷学习之旅一)

    标题党, 其实这个主题改为"如何能快速的学习与实施敏捷"更贴切. 我在一家大型的外资金融企业,公司最近在大面积的实施敏捷转型,我的团队首先被选为试点团队,并实施得很好,最近我也和不 ...

  7. 为.net Core 3.0 WebApi 创建Linux守护进程

    前言 我们一般可以在Linux服务器上执行 dotnet <app_assembly.dll> 命令来运行我们的.net Core WebApi应用.但是这样运行起来的应用很不稳定,关闭终 ...

  8. echarts-liquidfill 水球显示小数点

    使用echarts-liquidfill.js的水球,水球上显示的文字可以使用chartOption.series[0].label.normal.formatter设置,想显示什么显示什么. var ...

  9. Hadoop集群搭建(二)~centos6.8的安装

    这篇记录在创建好的虚拟机中安装centos6.8 1,在虚拟机界面-选择编辑虚拟机设置 2,CD/DVD,选择使用ISO映像文件,找到安装包的位置,确定 3,回到虚拟机的界面,开启此虚拟机 4,安装 ...

  10. (转)协议森林09 爱的传声筒 (TCP连接)

    协议森林09 爱的传声筒 (TCP连接) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在TCP协议与"流" ...