博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js 栈 与 event loop
阅读量:5914 次
发布时间:2019-06-19

本文共 3120 字,大约阅读时间需要 10 分钟。

首先,我们可以看到一张图,里面讲述了一次事件循环所需要执行的内容。首先,js主线程执行任务,进行压栈操作,当任务执行完毕,然后紧接着执行出栈操作。其中如果遇到异步函数,如settimeout(宏任务),放入队列中,下一次循环执行,而promise等放入相应的异步模块中,等待主线程执行完毕。主线程执行完毕,会从promise等异步模块中取出当前任务中添加的微任务,依次执行完成。就结束了一次事件循环

栈操作: function bar() { console.log(1); }

function foo() { console.log(2); far(); }

setTimeout(() => { console.log(3) });

foo(); 出栈入栈图:

队列,事件循环: console.log('script start');

setTimeout(function() {

console.log('setTimeout');

}, 0);

Promise( function(resolve,reject){

console.log('promise1');

resolve()

}).then(function() {

console.log('promise2');

});

console.log('script end'); 这一段代码的输出是什么?

首先要确定哪些是宏任务,哪些是微任务:在js中,settimeout,setinterval,setimmediate(node环境中才有)属于标准的宏任务,而promise.then与prossis.nextTick(node)、mutation observe属于常见微任务,主要是需要异步的执行任务而又不需要分配一个新的 宏任务,这样便可以减小一点性能的开销

js是单线程执行的,它的异步任务与多线程语言类似,也是将事件存放在队列中,依次执行,但是并不会开新线程执行,而是等待一个宏任务执行完毕,再从队列中取到另外一个宏任务执行。宏任务与微任务的关系就在于,event runloop 一次循环执行,会执行一个宏任务以,然后会执行当前宏任务内的所有微任务,最后循环结束,开启下一次循环。

回退再来看上面那段代码,很简单: script start promise1 script end proise2(微任务) settimeout(宏任务)

宏任务与宏任务 微任务与微任务 优先级问题:

setImmediate(()=>{

console.log('setImmediate1')

setTimeout(()=>{

console.log('setTimeout1') 复制代码

},0)

}) setTimeout(()=>{

console.log('setTimeout2')

process.nextTick(()=>{console.log('nextTick1')})

setImmediate(()=>{

console.log('setImmediate2')复制代码

})

},0) 如果从图中判断,由上自下,优先级一次排列,timer >io > check,那么我们可以判断:

1.主线程执行,setimmediate1进栈,判断异步执行,加入队列中并出栈,settimeout2进栈,判断异步执行加入到执行队列中,主线程执行完毕。

2.开启新的event loop ,执行timer异步模块,执行settimeout2,并将nextTick与setImmediate2加入到异步模块,settimout2执行结束立刻执行nextTick,然后进入check模块,执行完setImmediate1,并将settimout1加入队列,之后执行setImmediate2,结束后执行settimout1 但是执行结果并不如意

第一种: setImmediate1 setTimeout2 nextTick1 setImmediate2 setTimeout1

第二种: setImmediate1 setTimeout2 nextTick1 setTimeout1 setImmediate2

第三种:setTimeout2 nextTick1 setImmediate1 setImmediate2 setTimeout1

settimout与setimmediate并没有执行优先级,当settiemout设置触发时间为0的时候,浏览器仍旧会给它加上一个最低触发时间4ms,虽然都是立刻执行函数,如果settimout需要等待4ms执行,那么setimmediate先执行,如果不需要,settimout具有更高的优先级。 再来看一个例子: setImmediate(()=>{

console.log('setImmediate1')

})

setTimeout(()=>{

console.log('setTimeout3')

},0)

setImmediate(()=>{

console.log('setImmediate3')

})

setTimeout(()=>{

console.log('setTimeout4')

},0)

setImmediate(()=>{

console.log('setImmediate4')

}) 执行结果只有两种:

1.setImmediate1 setImmediate3 setImmediate4 setTimeout3 setTimeout4

2.setTimeout3 setTimeout4 setImmediate1 setImmediate3 setImmediate4

再一次说明settimout与setimmediate执行顺序是不定的,但是另外一点是,异步执行方式并不是完全按照加入队列的先后顺序执行,会执行完timer模块内的立刻执行函数与check模块内的立刻执行函数。这一点与老版本的node执行方式有些不一样,以前是一个循环完成后接上下一次循环,现在执行settimout会依次遍历所有的settimout执行完毕,setimmediate也是同样的操作

关于优先级的另一个比较清晰的版本:

观察者优先级

在每次轮训检查中,各观察者的优先级分别是:

idle观察者 > I/O观察者 > check观察者。

idle观察者:process.nextTick

I/O观察者:一般性的I/O回调,如网络,文件,数据库I/O等

check观察者:setImmediate,setTimeout

可以明确的一点是,nextTick执行优先级是高于pormise的,

new Promise(function (resolve, reject) {

console.log('promise')resolve()复制代码

}).then(function() {

console.log('then')复制代码

})

process.nextTick(()=>{console.log('nextTick1')})

执行结果始终是 promise nextTck1 then

在事件循环中有一点忘记提及的是gui渲染线程,虽然它不属于js线程,但是由于js单线程,gui渲染也被加入到队列中,作为一个任务使用,类似微任务,不会当成一个单独的宏任务执行,但是优先级最低,即一次event loop执行完主线程,以及所有当前线程微任务后,才执行gui渲染线程。

转载地址:http://nvqpx.baihongyu.com/

你可能感兴趣的文章
ylbtech-LanguageSamples-Nullable(可以为 null 的类型)
查看>>
Android N 多窗口模式,你需要知道的一切
查看>>
[Tips]Windows7和Rational Rose 2003 Enterprise Edition兼容性问题
查看>>
dropify,不错的图片上传预览插件
查看>>
Linux用init命令关机、重启、切换模式
查看>>
[CareerCup] 14.2 Try-catch-finally Java中的异常处理
查看>>
转帖:网站服务架构
查看>>
[Step By Step]SAP HANA PAL三次指数平滑算法实现TRIPLESMOOTH
查看>>
利用JavaScript选择GridView行
查看>>
Linux - 设置光盘,开机自动挂载。
查看>>
第 35 章 snmpd - daemon to respond to SNMP request packets.
查看>>
Angular 4 管道
查看>>
怎样为virtualbox添加新的分辨率
查看>>
Cocos2D-x权威指南:核心类成员CCNode
查看>>
Windows7下python的scipy库的安装
查看>>
jquery对ajax的error内的XMLHttpRequest返回的exception获取里面的信息
查看>>
2.检查网络状态
查看>>
有配置文件有关的测试
查看>>
ASP.Net简单的交互案例
查看>>
hihoCoder #1043 : 完全背包(板子题)
查看>>