实例分析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 相关文章推荐
Dom加载让图片加载完再执行的脚本代码
May 15 Javascript
jquery遍历筛选数组的几种方法和遍历解析json对象
Dec 13 Javascript
jquery通过select列表选择框对表格数据进行过滤示例
May 07 Javascript
JavaScript和CSS交互的方法汇总
Dec 02 Javascript
javascript实现根据时间段显示问候语的方法
Jun 18 Javascript
js实现搜索框关键字智能匹配代码
Mar 26 Javascript
精通JavaScript的this关键字
May 28 Javascript
Node.js的Koa框架上手及MySQL操作指南
Jun 13 Javascript
jQuery实现的粘性滚动导航栏效果实例【附源码下载】
Oct 19 jQuery
利用vue+elementUI实现部分引入组件的方法详解
Nov 22 Javascript
微信小程序 image组件遇到的问题
May 28 Javascript
RxJS的入门指引和初步应用
Jun 15 Javascript
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
Yii 2.0实现联表查询加搜索分页的方法示例
2017/08/02 PHP
页面中body onload 和 window.onload 冲突的问题的解决
2009/07/01 Javascript
Exitjs获取DataView中图片文件名
2009/11/26 Javascript
用jquery实现的模拟QQ邮箱里的收件人选取及其他效果(一)
2011/01/06 Javascript
简单漂亮的js弹窗可自由拖拽且兼容大部分浏览器
2013/10/22 Javascript
jquery监听div内容的变化具体实现思路
2013/11/04 Javascript
js获取上传文件大小示例代码
2014/04/10 Javascript
使用js画图之饼图
2015/01/12 Javascript
深入理解JavaScript编程中的原型概念
2015/06/25 Javascript
Javascript设计模式理论与编程实战之简单工厂模式
2015/11/03 Javascript
基于canvas实现的钟摆效果完整实例
2016/01/26 Javascript
jQuery.form.js插件不能解决连接超时(timeout)的原因分析及解决方法
2016/10/14 Javascript
简单实现nodejs上传功能
2017/01/14 NodeJs
JS运动特效之任意值添加运动的方法分析
2018/01/24 Javascript
微信小程序:数据存储、传值、取值详解
2019/05/07 Javascript
layer iframe 设置关闭按钮的方法
2019/09/12 Javascript
Vue使用vue-draggable 插件在不同列表之间拖拽功能
2020/03/12 Javascript
Python中关于使用模块的基础知识
2015/05/24 Python
pandas string转dataframe的方法
2018/04/11 Python
Python做智能家居温湿度报警系统
2018/09/25 Python
Django 1.10以上版本 url 配置注意事项详解
2019/08/05 Python
在python中实现求输出1-3+5-7+9-......101的和
2020/04/02 Python
Python request中文乱码问题解决方案
2020/09/17 Python
使用bandit对目标python代码进行安全函数扫描的案例分析
2021/01/27 Python
美体小铺法国官方网站:The Body Shop法国
2020/06/04 全球购物
Linux上比较文件的命令都有哪些
2012/02/24 面试题
什么是抽象
2015/12/13 面试题
幼儿园教师自我鉴定
2014/03/20 职场文书
交通事故调解协议书
2014/04/16 职场文书
机械系毕业生求职信
2014/05/28 职场文书
创建绿色社区汇报材料
2014/08/22 职场文书
2014年领导班子工作总结
2014/12/11 职场文书
刑事上诉状(量刑过重)
2015/05/23 职场文书
2015新员工工作总结范文
2015/10/15 职场文书
《丑小鸭》教学反思
2016/02/19 职场文书
详解如何使用Nginx解决跨域问题
2022/05/06 Servers