实例分析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 相关文章推荐
jscript之List Excel Color Values
Jun 13 Javascript
JavaScript 异步调用框架 (Part 1 - 问题 &amp; 场景)
Aug 03 Javascript
分别用marquee和div+js实现首尾相连循环滚动效果,仅3行代码
Sep 21 Javascript
jQuery获取和设置表单元素的方法
Feb 14 Javascript
js 与 php 通过json数据进行通讯示例
Mar 26 Javascript
巧用jQuery选择器提高写表单效率的方法
Aug 19 Javascript
简单理解Vue条件渲染
Dec 03 Javascript
jquery使用EasyUI Tree异步加载JSON数据(生成树)
Feb 11 Javascript
JS实现加载时锁定HTML页面元素的方法
Jun 24 Javascript
Vue使用Proxy监听所有接口状态的方法实现
Jun 07 Javascript
javascript事件循环event loop的简单模型解释与应用分析
Mar 14 Javascript
JS开发前端团队展示控制器来为成员引流
Aug 14 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
分享8个最佳的代码片段在线测试网站
2013/06/29 PHP
php读取图片内容并输出到浏览器的实现代码
2013/08/08 PHP
PHP基于ORM方式操作MySQL数据库实例
2017/06/21 PHP
php的RSA加密解密算法原理与用法分析
2020/01/23 PHP
PHP时间相关常用函数用法示例
2020/06/03 PHP
随机显示经典句子或诗歌的javascript脚本
2007/08/04 Javascript
jQuery live
2009/05/15 Javascript
Juqery Html(),append()等方法的Bug解决方法
2010/12/13 Javascript
Js从头学起(基本数据类型和引用类型的参数传递详细分析)
2012/02/16 Javascript
使用AmplifyJS组件配合JavaScript进行编程的指南
2015/07/28 Javascript
jQuery的ready方法实现原理分析
2016/10/26 Javascript
JS中使用 after 伪类清除浮动实例
2017/03/01 Javascript
3种vue组件的书写形式
2017/11/29 Javascript
vue项目关闭eslint校验
2018/03/21 Javascript
Vue项目全局配置微信分享思路详解
2018/05/04 Javascript
详解Vue2 添加对scss的支持
2019/01/02 Javascript
基于Express框架使用POST传递Form数据
2019/08/10 Javascript
vue+webpack 更换主题N种方案优劣分析
2019/10/28 Javascript
angular *Ngif else用法详解
2020/12/15 Javascript
[56:00]DOTA2上海特级锦标赛主赛事日 - 4 胜者组决赛Secret VS Liquid第一局
2016/03/05 DOTA
python3使用urllib模块制作网络爬虫
2016/04/08 Python
Python列出一个文件夹及其子目录的所有文件
2016/06/30 Python
python 从文件夹抽取图片另存的方法
2018/12/04 Python
Pyqt QImage 与 np array 转换方法
2019/06/27 Python
python实现通过flask和前端进行数据收发
2019/08/22 Python
python实现的生成word文档功能示例
2019/08/23 Python
Tensorflow轻松实现XOR运算的方式
2020/02/03 Python
python和php哪个更适合写爬虫
2020/06/22 Python
Python 字符串池化的前提
2020/07/03 Python
如何在网站上添加谷歌定位信息
2016/04/16 HTML / CSS
工商学院毕业生自荐信
2013/11/12 职场文书
尊老爱幼演讲稿
2014/09/04 职场文书
情人节活动总结范文
2015/02/05 职场文书
女性励志书籍推荐
2019/08/19 职场文书
导游词之四川熊猫基地
2020/01/13 职场文书
详解JAVA中的OPTIONAL
2021/06/14 Java/Android