在JavaScript中,有两种任务:
宏任务(MacroTask):
- script(整体代码)、
- setTimeout、
- setInterval、
- setImmediate(浏览器暂时不支持,只有IE10支持)、
- I/O、
- UI Rendering
微任务(MicroTask): - process.nextTick(node独有)、
- Promise、
- Async/Await(实际就是promise)、
- MutationObserver(html5新特性)
- 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
- 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
- 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
- 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。
————————————分割线————————————————————
看完图文解释开始迷糊了,赶紧先看几个例子:
例1:
console.log('script start')
setTimeout(function(){
console.log('settimeout')
})
console.log('script end')
// script start
// script end
// settimeout
例2:
console.log('script start')
let promise1 = new Promise(function (resolve) {
console.log('promise1')
resolve()
console.log('promise1 end')
}).then(function () {
console.log('promise2')
})
setTimeout(function(){
console.log('settimeout')
})
console.log('script end')
// script start
// promise1
// promise1 end
// script end
// promise2
// settimeout
执行2:Promise本身是同步的立即执行函数,所以输出promise1,
步骤3:resolve()的作用是改变Promise对象的状态,并不会阻断函数的执行,所以会执行输出promise1 end。then()回调是微任务,放到微任务队列
步骤4:settimeout宏任务,放进宏任务队列
步骤6:按顺序执行完微任务队列中的所有微任务
步骤7:微任务队列执行完,开始执行下一个宏任务
例3:
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// script start
// async1 start
// async2
// script end
// async1 end
步骤2:执行async1函数,输出async1 start,
步骤3:遇到了await语句,立即执行表达式,执行await方法
步骤4:await后面的语句放入微任务队列,相当于让出了线程,跳出了async函数体
步骤6:执行微任务队列任务,执行完看宏任务队列,为空,执行完成
例4:
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout
————————————分割线————————————————————
我觉得这对段放前面不好理解,先把上文搞定,再去理解下面的话:
Event Loop,即事件循环,是指浏览器或Node的一种解决JavaScript单线程运行时不会阻塞的一种机制,是js实现异步的一种方法,也是js的执行机制。
JavaScript是单线程语言,但是可以开启同步任务和异步任务。
JavaScript中包含一个主线程(main-thread)和调用栈(call-stack),调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。
在一个线程中,事件循环是唯一的,但是任务队列(宏任务和微任务)可以拥有多个,任务队列是先进先出的数据结构
参考:https://juejin.cn/post/6844903764202094606#heading-2
https://juejin.cn/post/6844903512845860872#heading-6
https://juejin.cn/post/6844904079353708557
https://www.cnblogs.com/lideyao/p/12022717.html