js事件循环(同步函数及异步函数)
Event Loop(事件循环)
Event Loop 即事件循环,是指浏览器或 Node 的⼀种解决 javaScript 单线程运⾏时不会阻塞的⼀种机制,也就是我们经常使⽤异步的原理。
之所以称之为事件循环,是因为它经常按照类似如下的⽅式来被实现:
while(queue.waitForMessage()){
queue.processNextMessage();
}
如果当前没有任何消息,queue.waitForMessage() 会同步地等待消息到达. 每⼀个消息完整地执⾏后,其它消息才会被执⾏。 这为程序的分析提供了⼀些优秀的特性,包括:⼀个函数执⾏时,它永远不会被抢占,并且在其他代码运⾏之前完全运⾏(且可以修改此函数操作的数据
问:为什么 JavaScript 是单线程的?
答:JavaScript 的单线程,与它的⽤途有关。作为浏览器脚本语⾔,JavaScript 的主要⽤途是与⽤户互动,以及操作 DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。⽐如,假定 JavaScript 同时有两个线程,⼀个线程在某个 DOM 节点上添加内容,另⼀个线程删除这个节点,这时如果删除节点的操作在添加内容之前完成,后者将会报错。
浏览器中的 Event Loop
▶  在 JavaScript 中, 任务被分为两种:
⼀种宏任务( MacroTask) 也叫 Task,定义:当前调⽤栈中执⾏的代码成为宏任务。(主代码块,定时器等等);
⼀种叫微任务( MicroTask)。定义:当前(此次事件循环中)宏任务执⾏完,在下⼀个宏任务开始之前需要执⾏的任务,可以理解为回调事件。(promise.then())
MacroTask(宏任务)- tasks
包括:script 全部代码、 setTimeout、 setInterval)、 I / O、 UI Rendering。
MicroTask(微任务)- jobs
包括: Promise、 MutationObserver
微任务的执⾏优先级⽐宏任务⾼,当微任务全部执⾏完毕之后(微任务队列为空),才执⾏宏任务。
Javascript 有⼀个 main thread 主线程和 call-stack 执⾏栈,所有的任务都会被放到执⾏栈等待主线程执⾏。
1. 所有同步任务都在主线程上执⾏,形成⼀个执⾏栈 (Execution Context Stack)。
2. ⽽异步任务会被放置到 Event Table, 当异步任务有了运⾏结果, 就将该函数移⼊任务队列(Event Queue)。
3. ⼀旦执⾏栈中的所有同步任务执⾏完毕,引擎就会读取任务队列,然后将任务队列中的第⼀个任务压⼊执⾏栈中运⾏。
4. 主线程不断重复第三步,也就是"只要主线程空了,就会去读取任务队列"。该过程不断重复,这就是所谓的 事件循环。典型题
例⼀
setTimeout(()=>{
console.log("1");
},0);
var obj ={
func:function(){
setTimeout(function(){
console.log("2");
},0);
return new Promise(function(resolve){
console.log("3");
resolve();
});
}
};
obj.func().then(function(){
console.log("4");
});
console.log("5");
输出结果: 3 5 4 1 2
脚本执⾏完毕之后,微任务队列和宏任务队列的状态如下:
主线程:35
微任务:4
宏任务:12
await和async使用方法执⾏完主线程,然后先后执⾏微任务和宏任务,得出输出结果3 5 4 1 2
例⼆:
async function async1(){
await async2();//这⾏代码可以看成是solve(async2).then(()=>{console.log(1)})
console.log("1");
}
async function async2(){
console.log("2");
}
console.log("3");
async1();
new Promise(resolve =>{
console.log("4");
resolve();
})
.then(function(){
console.log("5");
setTimeout(function(){
console.log("6");
},0);
})
.then(function(){
console.log("7");
});
setTimeout(function(){
console.log("8");
},0);
console.log("9");
脚本执⾏完毕之后,微任务队列和宏任务队列的状态如下:
主线程:3249
微任务:15
宏任务:86
这时候,微任务队列不为空,按顺序执⾏微任务:
主线程:324915
微任务:7
宏任务:86
执⾏完 第⼀个then 之后,微任务队列⼜增加了⼀个微任务 (第⼆个then),所以继续执⾏微任务:
主线程:3249157
微任务:
宏任务:86
这时候微任务队列已经为空,所以开始执⾏宏任务:
主线程:324915786
微任务:
宏任务:
因此输出结果是:3 2 4 9 1 5 7 8 6
Ref
shuting’s small Share

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。