同步任务和异步任务
- js执行任务是单线程的,代码从上往下按顺序执行
- 为了解决I/O读写,定时器延时等阻塞代码执行,提出了任务的同步执行和异步执行
- 一般情况,同步任务优先于异步任务执行
- 常见的异步执行的任务有: setTimeout, setInterval, ajax异步请求,nodeJs文件的异步读写等。
例:
setTimeout(()=>{
console.log("异步任务")
}, 0)
console.log("同步任务")
// 输出为: 同步任务 异步任务
再例:
function sleep(n) {
var start = new Date().getTime();
while (true) {
if (new Date().getTime() - start > n) {
break;
}
}
}
setTimeout(()=>{
console.log("异步任务")
}, 3000)
sleep(10000)
在这个例子中会发现定时器输出远超3s,其大致执行过程如下:
- 整个js代码压入执行栈中
- 代码从上到下同步任务进入主线程执行,异步任务依次进入Event Table并注册回调函数,同时开始计时
- js引擎monitoring process进程监听主线程执行
- Event Table中的计时时间到,对应的回调函数推入Event Queue中(需要注意的是对于setIntervel,是每隔指定的时间将回调推入Event Queue中)
- 主线程(10000)时间到, js引擎监听到主线程为空,将event Queue中的回调函数推入主线程执行
宏任务和微任务
js对任务的执行是Event Loop,所有任务都进入到了Event Queue中,因而需要更为详细的任务划分:宏任务和微任务。
常见的宏任务: 包括整体代码script,setTimeout,setInterval
常见的微任务:Promise,process.nextTick
setTimeout(function() {
console.log('setTimeout');
},0)
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
上例执行过程:
- 整个代码作为script宏任务Event Queue进入主线程执行
1.1 setTimeout分发到宏任务Event Queue中
1.2 new Promis 直接执行,输出 promise,then()回调函数分发到其宏任务所对应的微任务Event Queue
1.3 直接执行最后的打印,输出 console,script宏任务执行完毕 - script宏任务执行完毕后开始执行其对微任务then()回调函数,输出then,script宏任务对应的微任务执行完毕
- 开始执行setTimeout对应的宏任务,输出setTimeout
- 同级同时的宏任务或者微任务执行顺序是先进先出(Event //)
例:
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
// 1,7,6,8,2,4,3,5,9,11,10,12
了解更对,参考掘金 这一次,彻底弄懂 JavaScript 执行机制