Javascript
是单线程,事件驱动,异步处理IO
的编程语言。处理异步操作,在promise
对象出现之前有async,eventproxy,q等第三方库(它们很棒)。说道单线程,难道 JS 在进行IO
操作或者ajax
获取数据的时候就傻傻的等待(同步),阻塞线程不做任何事吗?当然不是,这都要归功于事件循环和异步机制。从被玩儿坏的setTimeout
说起吧~
异步编程
console.log('start')
setTimeout(function (){
console.log('tickta...tickta')
}, 3000)
console.log('end')
//start
//end
// 3 secs later...
//tickta...tickta
此时一直使用C语言的同学可能感到匪夷所思了。「笑」
事件循环机制
JS 有一个主线程,用来处理事件。当js开始运行时,把所有非回调函数
依次放到JS主栈
,此例中setTimeout
也是非回调函数
,它执行的效果是在工作线程中增加一个计时器。还有一些工作线程
(来自Node环境
或者浏览器环境
,浏览器环境下应该叫Web API
),来处理文件操作,数据库读写操作,ajax请求。每当工作线程
完成一件工作就要通知主线程,通知方法就是把这些通知(回调函数
)放到任务队列
(task queue)里面。当JS主栈
空了以后——可以理解是执行了一轮——就从任务队列
里面依次取出回调函数
放入主栈执行。如果回调函数里面还有回调函数就把它们放入任务队列等待下一轮运行。用一张图来说明
异步任务分两种,有宏任务
(macro-task)和微任务
(micro-task)。JS引擎按照不同类型把任务分配到这两个队列,首先从macro-queue
中取出一个任务执行,然后取出micro-queue
中所有任务依次执行,再取出macro-queue
中一个任务执行,如此循环直到队列中的任务执行完毕。
两个类别的分类具体如下:
macro-task: script(整体代码),setTimeout,setInterval,setImmediate,I/O,UI rendering
micro-task: process.nextTick,Promise,Object.observe,MutationObserver
process.nextTick > promise.then > setTimeout > setImmediate
如果是浏览器环境,执行顺序也有依赖于实现。Chrome,Firefox,IE都不一样,node环境和Chrome一样
Promise 对象
Promise
对象的初始化需要重写(说重写可能对熟悉Java的同学比较好理解,或者说赋给他一个)它的function(resolve, reject){}
方法,该方法内部的代码会立刻执行,就好象它们直接写在函数外面一样。如果执行了resolve那么代表任务成功,将来会执行then里面的代码,如果执行了reject将来会执行catch里面的代码
setTimeout(function() {
console.log(1)
}, 0)
var p = new Promise(function(resolve, reject) {
console.log(2)
for(var i=0; i<10000; i++) {
i === 9999 && resolve()
}
console.log(3)
}).then(function() {
console.log(4)
}).then(function() {
console.log(5)
}
console.log(6)
执行结果
2
3
6
4
5
1
先执行macro-queue
的一个任务,也就是 script ,然后依次执行micro-queue
的所有任务,也就是 then 里面的,再执行macro-queue
的一个任务,也就是 setTimeout
参考资料:
知乎上关于 Promise 的考证
一个可视化代码执行过程,有点小 bug
Viemo 上关于事件循环的演讲,需要科学上网
浏览器环境下的事件循环
除非注明,嗯VIEW文章均为原创,转载请以链接形式标明本文地址
本文地址:https://www.umview.com/javascript-eventloop-promise
还不快抢沙发