如何理解EventLoop--浏览器篇
前言
最近在准备春招,刷到了JS中的主要运行机制--Event Loop,觉得它的实现思路有必要整理一下,以防忘记。关于它在浏览器上的实现,我结合了自己的理解以及示例代码,想用最通俗的语言表达出来。如果在文中出现书写错误的地方,欢迎大家留言一起探讨。
正文
关于Event Loop,宏任务,微任务的概念不再此赘述了。
概念
进入主题,我理解的浏览器的事件循环Event Loop,以及执行一个JavaScript代码的流程如下:
- 一开始整段脚本作为第一个宏任务执行;
- 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列;
- 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空;如果在执行微任务的过程中,又产生了微任务,那么会加入到队列的末尾,也会在这个周期被调用执行;
- 执行浏览器 UI 线程的渲染工作;
- 执行队首新的宏任务,回到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--浏览器篇的更多相关文章
- 我是这样理解EventLoop的
我是这样理解EventLoop的 一.前言 众所周知,在使用javascript时,经常需要考虑程序中存在异步的情况,如果对异步考虑不周,很容易在开发中出现技术错误和业务错误.作为一名合格的jav ...
- [Web] 深入理解现代浏览器
转载: https://blog.csdn.net/qihoo_tech/article/details/91921777 奇技指南 身为前端,你真正深入理解了浏览器吗? 本文来自公众号奇舞周刊,作者 ...
- C#串口通讯教程 简化一切 只保留核心功能 这可能是最易于理解的一篇教程
C#串口通讯教程 简化一切 只保留核心功能 这可能是最易于理解的一篇教程 串口的定义,请自行了解. C#操作串口通讯在.Net强大类库的支持下,只需要三个步骤: 1 创建 2 打开 3 发送/接受 ...
- 前端面试总结——http、html和浏览器篇
1.http和https https的SSL加密是在传输层实现的. (1)http和https的基本概念 http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和 ...
- iOS开发:深入理解GCD 第一篇
最近把其他书籍都放下了,主要是在研究GCD.如果是为了工作,以我以前所学的GCD.NSOperation等知识已经足够用了,但学习并不仅仅知识满足于用它,要知其然.并且知其所以然,这样才可以不断的提高 ...
- 15分钟理解HTTPS——通俗篇
| 导语 它很深奥吗?你肯定常常见过它,使用它,甚至离不开它... 它很浅显吗?你可能觉得看透它,理解它,甚至懂它... 让我们用15分钟,不那么学术地将它的深挖到底~ 什么?如何证明我是我?本文要上 ...
- 理解 EventLoop
链接 链接 node 浏览器 执行顺序有差异 macrotask microtask 一个线程会有 堆 栈 消息队列; 栈函数执行是用的, 堆用了存放定义的对象, 消息队列来处理异步的操作 a() ...
- 理解http浏览器的协商缓存和强制缓存
阅读目录 一:浏览器缓存的作用是什么? 二:理解协商缓存 1 Last-Modified/if-Modify-Since 2 ETag/if-None-Match 三:理解强制缓存 回到顶部 一:浏览 ...
- Range对象理解,浏览器兼容性,获取鼠标光标位置
一.关于浏览器的兼容性 目前主要有3种关于range的类似的对象,分别是W3C range 对象,Mozzlia selection ,ie TextRange 关于这三种的区别,请查看文档 http ...
- iOS开发:深入理解GCD 第二篇(dispatch_group、dispatch_barrier、基于线程安全的多读单写)
Dispatch Group在追加到Dispatch Queue中的多个任务处理完毕之后想执行结束处理,这种需求会经常出现.如果只是使用一个Serial Dispatch Queue(串行队列)时,只 ...
随机推荐
- 造轮子系列(三): 一个简单快速的html虚拟语法树(AST)解析器
前言 虚拟语法树(Abstract Syntax Tree, AST)是解释器/编译器进行语法分析的基础, 也是众多前端编译工具的基础工具, 比如webpack, postcss, less等. 对于 ...
- 使用D3.js构建实时图形
首先你需要在计算机上安装Node和npm. 数据的可视化表示是传递复杂信息的最有效手段之一,D3.js提供了创建这些数据可视化的强大工具和灵活性. D3.js是一个JavaScript库,用于使用SV ...
- 续python学习(一)
接上面没写完的知识点继写. 当然,这些知识点都很简单,可能没必要花费太多时间去记忆,多写写代码就会了. 5.字符串的使用.索引和切片是字符串主要的两个应用.索引:顾名思义就是找出某个字符在一个字符串中 ...
- 最适合初学者的一篇 Ribbon 教程
什么是 Ribbon Ribbon 是一个基于 HTTP 和 TCP 的 客服端负载均衡工具,它是基于 Netflix Ribbon 实现的. 它不像 Spring Cloud 服务注册中心.配置中心 ...
- 如何在Flutter中使用flutter_markdown
很多博客,论坛都支持markdown语法,flutter也有支持markdown语法的插件flutter_markdown 安装依赖 dependencies: flutter: sdk: flutt ...
- UIButton左边图片右边文字的做法
UIImage *yuyinImage = [UIImage imageNamed:@"yuyin.png"]; [soundButton setImage:yuyinImage ...
- 网络安全从入门到精通 (第二章-6) 后端基础PHP—表单验证
本文内容: 什么是表单? 如何创建一个表单: 接收并验证: PHP和数据库交互 1,什么事表单? 表单在网页中主要负责数据采集. 表单由三部分组成: 表单标签:这里面包含了处理表单数据所用动态脚本的U ...
- Python - 面向对象(二)类方法、静态方法
面向对象的各种方法 静态方法 - @staticmethod class Person(): name = "cool guy" @staticmethod def static( ...
- Python - 面向对象(三)公共变量,受保护变量,私有变量
前言 在Python的类里面,所有属性和方法默认都是公共的:但Python也可以设置受保护.私有类型的变量or方法 受保护类型的变量.方法 一般称为:protected变量 #!/usr/bin/en ...
- Rust入坑指南:齐头并进(下)
前文中我们聊了Rust如何管理线程以及如何利用Rust中的锁进行编程.今天我们继续学习并发编程, 原子类型 许多编程语言都会提供原子类型,Rust也不例外,在前文中我们聊了Rust中锁的使用,有了锁, ...