Event Loop事件循环,看完你总会有点收获!

栏目: Node.js · 发布时间: 6年前

内容简介:我们都知道JavaScript是单线程的,这是它语音特性决定的,因为的主要用途 在于一些I/O操作,Dom操作等,单线程为它提高了效率,但同时有很多操作,比如读取文件,Ajax获取数据等,都是一些比较耗时的操作,用户等不了太长时间,因此衍生出了事件循环这个概念。在JavaScript中,我们把队列分为两种,一种是同步任务,在主线程是执行,只有一个任务执行完才可以执行下一个任务,一种是异步任务,它不进入主线程,而是通过另外一种方式,叫做例如上图中

我们都知道JavaScript是单线程的,这是它语音特性决定的,因为的主要用途 在于一些I/O操作,Dom操作等,单线程为它提高了效率,但同时有很多操作,比如读取文件,Ajax获取数据等,都是一些比较耗时的操作,用户等不了太长时间,因此衍生出了事件循环这个概念。

1.2 任务队列

在JavaScript中,我们把队列分为两种,一种是同步任务,在主线程是执行,只有一个任务执行完才可以执行下一个任务,一种是异步任务,它不进入主线程,而是通过另外一种方式,叫做 任务队列

Event Loop事件循环,看完你总会有点收获!

例如上图中

  • 所有同步任务在Stack(栈)中执行
  • 其他耗时操作在下面的Queue(队列)中执行,一旦这些耗时操作执行完,就会放入队列中,先进先出
  • 一旦执行栈中任务执行结束,系统开始读取在队列中排队的任务,每访问一个队列,会执行完全部相同代码,比如setTimeout定时队列,再去下一个队列
  • 整个过程不停循环,称为事件循环

2 Node.js

2.1 事件循环

Node.js中也有Event Loop,不过它的机制和和浏览器中的略微不同

Event Loop事件循环,看完你总会有点收获!

如上图是经典的Node.js中的事件循环图,Node.js采用谷歌V8作为解析引擎,在I/O处理方面使用了libuv库,它是一个基于事件驱动的跨平台抽象层,封装了不同操作系统一些底层特性,对外提供统一的API,上图的事件循环机制是它里面的实现。 每次事件循环都包含了六个阶段:

  • timers阶段:包括setTimeout,setInterval等
  • pedding callbacks: 执行一些系统调用错误
  • idle,prepare: node内部使用
  • poll: 轮询阶段,检查I/O队列中定时器是否到时,例如(读取文件)
  • check:执行setImmediate() 设定的callbacks
  • close callbacks: 关闭回调

其中还有一些微任务和宏任务的概念 微任务:promise.then process.nextTick(),其中nextTick()执行会比前者快 宏任务:setTimeout setImmidate(ie) messageChannel等

微任务总是会比宏任务先执行

2.2例子

setTimeout(() => {
    console.log('timeout1');
    process.nextTick(()=>{
        console.log('nextTick1');
    })
}, 1000);
setTimeout(()=>{
    console.log('timeout2')
},1000)
复制代码

结果:timeout1 => timeout2 =>nextTick1 原因:首先都是外面宏任务,先执行时间队列,从上到下依次执行完timeout1=>timeout2,执行完后,到下一个队列,执行nextTick()

let fs = require('fs');
fs.readFile('./index.html',function(){ 
    setImmediate(function(){
        console.log('setImmediate')
    });
    setTimeout(function(){
        console.log('setTimeout')
    },0); // ->4
})
复制代码

结果:setImmediate => setTimeout 原因:读取文件是I/O操作是在poll轮询阶段,读取完后下一阶段是check,看有没有setImmediate,所以先执行这个,再执行setTimeout

let fs = require('fs');
setTimeout(function(){
    Promise.resolve().then(()=>{
        console.log('then2');
    })
},0);
Promise.resolve().then(()=>{
    console.log('then1');
});
fs.readFile('./index.html',function(){
    process.nextTick(function(){
        console.log('nextTick')
    })
    setImmediate(()=>{
        console.log('setImmediate')
    });
});

复制代码

结果:then1 => then2=> nextTick => setImmediate 原因:首先看最外面有微任务Promise.then,所以then1,接着到时间队列,times,执行then2,times => poll 是不同阶段,每执行不同阶段, process.nextTick 不属于事件循环的任何一个阶段,它属于该阶段与下阶段之间的过渡, 即本阶段执行结束, 进入下一个阶段前, 所要执行的回调。所以 都要检查当前有没有promise,或者nextTick,如果有,先执行这些,有nextTick,再执行setImmediate


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

首席产品官1 从新手到行家

首席产品官1 从新手到行家

车马 / 机械工业出版社 / 2018-9-25 / 79

《首席产品官》共2册,旨在为产品新人成长为产品行家,产品白领成长为产品金领,最后成长为首席产品官(CPO)提供产品认知、能力体系、成长方法三个维度的全方位指导。 作者在互联网领域从业近20年,是中国早期的互联网产品经理,曾是周鸿祎旗下“3721”的产品经理,担任CPO和CEO多年。作者将自己多年来的产品经验体系化,锤炼出了“产品人的能力杠铃模型”(简称“杠铃模型”),简洁、直观、兼容性好、实......一起来看看 《首席产品官1 从新手到行家》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器