因为js是单线程,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。
js任务可以分为同步任务和异步任务,
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
异步任务:异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
一旦主线程上的同步任务执行完,就会读取任务队列里的事件任务。
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
event loop组成:
调用栈(call stack): 将函数事件压入栈中,执行完该事件,从栈中弹出。
微任务队列(microtask Queen):异步任务的promise的回调函数会被放入微任务队列中。微队列也叫jobs
宏任务队列(macrotask): 包含 setTimeout 、setInterval的回调函数。宏队列也叫tasks
js引擎在执行过程中有优先级之分,首先会执行js线程的主任务,也就是同步的事件,按执行的顺序依次放入调用栈中执行,输出执行结果后,出栈。直至主任务全部完成。
这时候去查找是否有微任务队列里是否有任务,如果有,就依次从该队列中取队首任务放入调用栈执行。
注:在执行微任务的过程中又产生了新的微任务,那么会加入到微任务的队列末尾,也在这个周期被调用执行。
当微任务队列也为空了,再去宏任务队列里查看是否有任务,有,则从队首依次取出放入调用栈中执行,。
event loop图解(源网络)
例子:
这里是引用
//1:第一步执行
console.log(1);
// 整个setTimeout被放入macrotask queue(宏队列)中队首位置,(编号为1)
setTimeout(() => {
console.log(2);
Promise.resolve().then(() => {
console.log(3)
});
});
// 第二步执行,这里new Promise({})是同步执行的
new Promise((resolve, reject) => {
console.log(4)
resolve(5)
}).then((data) => {// 但是这里的.then 是promise的回调函数,整个then 之后的放入到microtask queue(微队列)
console.log(data);
Promise.resolve().then(() => {
console.log(6)
}).then(() => {
console.log(7)
setTimeout(() => { // 此处setTimeout会在执行微任务的时候被添加到宏队列中,所以此题中最后输出
console.log(8)
}, 0);
});
})
setTimeout(() => { // 放入宏队列第二个位置
console.log(9);
})
console.log(10); // 主任务,第三步执行
最终输出结果是
1
4
10
5
6
7
2
3
9
8