node.js中对Event Loop事件循环的理解
javascript是单线程的,所以任务的执行都需要排队,任务分为两种,一种是同步任务,一种是异步任务。
同步任务是进入主线程上排队执行的任务,上一个任务执行完了,下一个任务才会执行。
异步任务是不进入主线程,而是进入一个 "任务队列" 里,"任务队列" 通知主线程,该异步任务才会进入主线程执行。
任务的运行机制如下:
1、所有同步任务在主线程上执行,形成一个 "执行栈",注意栈是先进后出的。
2、主线程外,有一个 "任务队列" ,只要异步任务处理完有结果了,就在 "任务队列" 中放置一个事件,注意队列是先进先出的。
3、一旦 "执行栈" 中所有同步任务执行完毕。系统读取 "任务队列" 中的事件,对应的异步任务。放入 "执行栈" 中,开始执行。
4、主线程不断重复第三步,这种循环从 "任务队列" 中读取事件处理的这种运行机制称为Event Loop(事件循环)。
"执行栈" 中的同步代码总是比 "任务队列"中的异步任务之前运行。
function fun() {
setTimeout(function () {
console.log('异步任务');
}, 0);
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
}
fun();
上面的代码,console.log代码写在setTimeout后面,但仍然先执行。
"任务队列" 是一个队列,队列的特性是先进先出。看下面代码:
function fun() {
console.log(1);
setTimeout(function () {
console.log(2);
setTimeout(function () {
console.log(3);
}, 0);
}, 0);
console.log(4);
}
fun();
输出结果为 1 4 2 3,打印 2 的setTimeout任务比打印 3 的setTimeout任务先进入队列,所以会先运行。
对于异步操作,像ajax,只有操作成功后返回结果,才会进入 "任务队列" 中,而不是调用的时候就放入队列中。看下面代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
function ajax() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://mail.163.com/', true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
};
}
function fun() {
console.log(1);
ajax();
setTimeout(function () {
console.log(2);
}, 1000);
console.log(3);
}
fun();
</script>
</body>
</html>
ajax() 与 setTimeout 谁先进入队列,谁先输出,是需要看两者消耗时间,谁更短。时间短的会先进入队列先运行。
setTimeout 与 setInterval 运行机制一样,都是在指定时间把事件插入到 "任务队列" 尾部。区别是前者只执行一次,后者可反复执行。
node.js 还为我们提供了,process.nextTick 和 setImmediate 与 "任务队列" 有关的方法。
process.nextTick 会把回调函数放在当前 "执行栈" 的尾部。也就是说是在读取 "任务队列" 之前运行。
function fun() {
console.log(1);
setTimeout(function () {
console.log(2);
}, 0);
process.nextTick(function () {
console.log(3);
process.nextTick(function () {
console.log(4);
});
});
process.nextTick(function () {
console.log(5);
});
console.log(6);
}
fun();
上面的代码会输出 1 6 3 5 4 2 ,注意process.nextTick会把回调函数放在 "执行栈" 的尾部。
同步代码最先输出 1 6,然后 3 的先放入尾部,然后 5 的跟在 3 后面。3先执行,然后把 4 放入到 5 的后面。5执行完后,再执行4,最后读取 "任务队列" 中的输出2。
setImmediate 会把回调函数放在当前 "任务队列" 的尾部。也就是下一次事件循环Event Loop时执行。
function fun() {
console.log(1);
setTimeout(function () {
console.log(2);
}, 0);
setImmediate(function () {
console.log(3);
});
console.log(4);
}
fun();
上面的代码是会输出 1 4 2 3 还是 1 4 3 2 是不确定的,因为setTimeout 与 setImmediate 都会在下一次事件循环Event Loop中触发,所以输出是不确定的。
node.js中对Event Loop事件循环的理解的更多相关文章
- 为什么JS是单线程?JS中的Event Loop(事件循环)?JS如何实现异步?setimeout?
https://segmentfault.com/a/1190000012806637 https://www.jianshu.com/p/93d756db8c81 首先,请牢记2点: (1) JS是 ...
- Event Loop事件循环,GET!
JS中比较让人头疼的问题之一要算异步事件了,比如我们经常要等后台返回数据后进行dom操作,又比如我们要设置一个定时器完成特定的要求.在这些同步与异步事件里,异步事件肯定是在同步事件之后的,但是异步事件 ...
- javascript的event loop事件循环
javascript的event loop事件循环 这是今天一个朋友发给我的一个面试题, 感觉还挺有意思的, 写个博客以供分享 先看看这个面试题目: 观察下面的代码,写出输出结果 console.lo ...
- js event loop事件循环
浏览器环境 以下两段代码是等价的.req对事件的回调设置,实际上就是当前主线程任务队列的任务. var req = new XMLHttpRequest(); req.open('GET', url) ...
- 浅谈 Event loop (事件循环)
从Event Loop谈JS的运行机制 先来理解一个概念: JS分为同步任务和异步任务 同步任务都在主线程上执行,形成一个执行栈 Execute Content Stack 主线程之外,事件触发线程管 ...
- 进程,线程,Event Loop(事件循环),Web Worker
线程,是程序执行流的最小单位.线程可与同属一个进程的其他线程共享所拥有的全部资源,同一进程中的多个线程之间可以并发执行.线程有就绪,阻塞,运行三种基本状态. 阮一峰大神针对进程和线程的类比,很是形象: ...
- JavaScript event loop事件循环 macrotask与microtask
macrotask 姑且称为宏任务,在很多上下文也被简称为task.例如: setTimeout, setInterval, setImmediate, I/O, UI rendering. mic ...
- [Node.js] Use nodejs-dashboard event loop delay with hrtime()
In this lesson, you will learn how to use the Formidable nodejs-dashboard event loop delay to identi ...
- js中(event)事件对象
事件对象 • 什么是事件对象? • 就是当你触发了一个事件以后,对该事件的一些描述信息 • 例如: ° 你触发一个点击事件的时候,你点在哪个位置了,坐标是多少 ° 你触发一个键盘事件的时候,你按的是哪 ...
随机推荐
- PostgresQL 中有没有rownum这样的,显示结果集的序号
select * from (select row_number() over() as rownum,tablename from pg_tables) t where rownum<10;
- 1.13.Mark1
[经济学人]双语阅读:律师事务所 标价更高 收益更少 Business 商业报道 Law firms 律师事务所 Charging more, getting less 标价更高,收益更少 L ...
- TypeScript语言学习笔记(2)
接口 // 在参数类型中定义约束 function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label ...
- 29.Spring-基础.md
目录 1.目的和作用 [toc] 2.概念 2.1框架的设计 2.2控制反转 2.3AOP [toc] 3. 3.1Spring六大模块 [toc] 1.目的和作用 解决对象的创建和以及对象依赖关系的 ...
- C# 模拟多线程下载文件
原地址:http://www.cnblogs.com/Opiece/p/4803836.html 客户端 public static string strContent = ""; ...
- 获取tensorflow中tensor的值
tensorflow中的tensor值的获取: import tensorflow as tf #定义变量a a=tf.Variable([[[1,2,3],[4,5,6]],[[7,8,9],[10 ...
- 初始C语言中的指针(翁凯男神MOOC)
运算符 & ● scanf("%d",&i); ●获得变量的地址,它的操作数必须是变量 ● int i; printf("%x",& ...
- redis 高级特性 不要太好用
Redis高级特性及应用场景 redis中键的生存时间(expire) redis中可以使用expire命令设置一个键的生存时间,到时间后redis会自动删除它. 过期时间可以设置为秒或者毫秒精度. ...
- vue 模拟下拉树
// 使用vue 做表格部分其他部分暂不修改 var app = new Vue({ el: "#freightTbl", watch: { //监听表格数据的变化[使用 watc ...
- 安装FP
一.安装Oracle 11.2 64-bit数据库 1.安装数据库软件并将SEINESCM数据库还原到服务器上, 2.配置监听和TNS信息 二.安装数据库32位客户端(为SSIS配套使用).安装ORA ...