实例分析js事件循环机制


Posted in Javascript onDecember 13, 2017

本文通过实例给大家详细分析了JS中事件循环机制的原理和用法,以下是全部内容:

var start = new Date()
setTimeout(function () {
 var end = new Date
 console.log('Time elapsed:', end - start, 'ms')
}, 500)
while (new Date() - start < 1000) {
}

有其他语言能完成预期的功能吗?Java, 在Java.util.Timer中,对于定时任务的解决方案是通过多线程手段实现的,任务对象存储在任务队列,由专门的调度线程,在新的子线程中完成任务的执行

js是单线程的

JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

函数调用栈和任务队列

实例分析js事件循环机制

调用栈

JS执行时会形成调用栈,调用一个函数时,返回地址、参数、本地变量都会被推入栈中,如果当前正在运行的函数中调用另外一个函数,则该函数相关内容也会被推入栈顶.该函数执行完毕,则会被弹出调用栈.变量也随之弹出,由于复杂类型值存放于堆中,因此弹出的只是指针,他们的值依然在堆中,由GC决定回收.

事件循环(event loop) & 任务队列(task queue)

JavaScript 主线程拥有一个执行栈以及一个任务队列

遇到异步操作(例如:setTimeout, AJAX)时,异步操作会由浏览器(OS)执行,浏览器会在这些任务完成后,将事先定义的回调函数推入主线程的任务队列(task queue)中,当主线程的执行栈清空之后会读取task queue中的回调函数,当task queue被读取完毕之后,主线程接着执行,从而进入一个无限的循环,这就是事件循环.

主线程执行栈 & 任务队列 循环执行,构成事件循环

结论

setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

另一个例子

(function test() {
 setTimeout(function() {console.log(4)}, 0);
 new Promise(function executor(resolve) {
 console.log(1);
 for( var i=0 ; i<10000 ; i++ ) {
 i == 9999 && resolve();
 }
 console.log(2);
 }).then(function() {
 console.log(5);
 });
 console.log(3);
})()

Macrotask & Microtask

macrotask 和 microtask 是异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。

macro-task: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, Promises(这里指浏览器实现的原生 Promise), Object.observe, MutationObserver

实例分析js事件循环机制

结论

全部代码(script) macrotask -> microtask queue (含有promise.then) -> macrotask(setTimeout) -> 下一个microtask

Node.js的事件循环

process.nextTick & setImmediate

process.nextTick指定的任务总是发生在所有异步任务之前

setImmediate指定的任务总是在下一次Event Loop时执行

process.nextTick(function A() {
 console.log(1);
 process.nextTick(function B(){console.log(2);});
});
setTimeout(function timeout() {
 console.log('TIMEOUT FIRED');
}, 0)
new Promise(function(resolve) {
 console.log('glob1_promise');
 resolve();
}).then(function() {
 console.log('glob1_then')
})
process.nextTick(function() {
 console.log('glob1_nextTick');
})
Javascript 相关文章推荐
js验证整数加保留小数点的简单实例
Dec 02 Javascript
javascript实现漂亮的拖动层,窗口拖拽特效
Apr 24 Javascript
javascript从作用域链谈闭包
Jul 29 Javascript
js实现搜索框关键字智能匹配代码
Mar 26 Javascript
javascript实现瀑布流加载图片原理
Feb 02 Javascript
JS给swf传参数的实现方法
Sep 13 Javascript
解决Vue 项目打包后favicon无法正常显示的问题
Sep 01 Javascript
JS编写兼容IE6,7,8浏览器无缝自动轮播
Oct 12 Javascript
利用d3.js制作连线动画图与编辑器的方法实例
Sep 05 Javascript
JS document文档的简单操作完整示例
Jan 13 Javascript
es6数组的flat(),flatMap()函数用法实例分析
Apr 18 Javascript
vue+flask实现视频合成功能(拖拽上传)
Mar 04 Vue.js
javascript实现QQ空间相册展示源码
Dec 12 #Javascript
自定义PC微信扫码登录样式写法
Dec 12 #Javascript
基于模板引擎Jade的应用(详解)
Dec 12 #Javascript
jquery获取transform里的值实现方法
Dec 12 #jQuery
JS排序算法之希尔排序与快速排序实现方法
Dec 12 #Javascript
将Sublime Text 3 添加到右键中的简单方法
Dec 12 #Javascript
详解vue渲染函数render的使用
Dec 12 #Javascript
You might like
桌面中心(四)数据显示
2006/10/09 PHP
使用eAccelerator加密PHP程序
2008/10/03 PHP
限制ckeditor上传图片文件大小的方法
2013/11/15 PHP
php使用curl发送json格式数据实例
2013/12/17 PHP
php+ajax实现图片文件上传功能实例
2014/06/17 PHP
PHP使用mysqldump命令导出数据库
2015/04/14 PHP
Django中通过定时任务触发页面静态化的处理方式
2018/08/29 PHP
在PHP中实现使用Guzzle执行POST和GET请求
2019/10/15 PHP
JQUERY获取form表单值的代码
2010/07/17 Javascript
再论Javascript的类继承
2011/03/05 Javascript
利用jQuery操作对象数组的实现代码
2011/04/27 Javascript
网页整体变灰白色(兼容各浏览器)实例
2013/04/21 Javascript
JavaScript实现非常简单实用的下拉菜单效果
2015/08/27 Javascript
Jquery中request和request.form和request.querystring的区别
2015/11/26 Javascript
基于javascript bootstrap实现生日日期联动选择
2016/04/07 Javascript
Base64(二进制)图片编码解析及在各种浏览器的兼容性处理
2017/02/09 Javascript
JavaScript函数节流的两种写法
2017/04/07 Javascript
node中Express 动态设置端口的方法
2017/08/04 Javascript
Bootstrap模态对话框用法简单示例
2018/08/31 Javascript
Nodejs监听日志文件的变化的过程解析
2019/08/04 NodeJs
微信小程序wx.navigateTo方法里的events参数使用详情及场景
2020/01/07 Javascript
ES6对象操作实例详解
2020/05/23 Javascript
[58:54]EG vs RNG 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
Django中的CACHE_BACKEND参数和站点级Cache设置
2015/07/23 Python
Python3学习笔记之列表方法示例详解
2017/10/06 Python
python smtplib发送带附件邮件小程序
2018/05/22 Python
对python产生随机的二维数组实例详解
2018/12/13 Python
python3编写ThinkPHP命令执行Getshell的方法
2019/02/26 Python
PyTorch搭建一维线性回归模型(二)
2019/05/22 Python
canvas 绘图时位置偏离的问题解决
2020/09/16 HTML / CSS
Gtech官方网站:地毯清洁器、吸尘器及园艺设备
2018/05/23 全球购物
捐款倡议书怎么写
2014/05/13 职场文书
党员考试作弊检讨书1000字
2015/02/16 职场文书
机关干部正风肃纪心得体会
2016/01/15 职场文书
教你如何使用Python实现二叉树结构及三种遍历
2021/06/18 Python
Python绘画好看的星空图
2022/03/17 Python