JavaScript 的 Even Loop

653 阅读2分钟

JavaScript 是一门单线程的语言,它的异步和多线程的实现是通过 Event Loop 事件循环机制来实现的

讲一下 Event Loop 的机制

大体三个部分组成

1、调用栈 Stack

2、消息队列 Message Queue

3、微任务队列 Microtask Queue

Event Loop 开始的时候会从全局栈开始逐行执行,遇到函数调用,会把函数压入到调用栈中,当函数返回后,会从调用栈中弹出

 案例 1function func1(){
    console.log(1);
 }
 function func2(){
    console.log(2);
    func1();
    console.log(3);
 }
 func2();
 
 **上述代码执行过程
 1、首先将 func2() 压入到调用栈中,执行内部代码,遇到console.log(2);输出2,执行完毕从调用栈中弹出console.log(2)
 2、遇到func1() 压入到调用栈中,执行内部代码,输出 console.log(1); 此时 func1执行完毕,从调用栈中弹出;
 3、执行console.log(3);到这里 func2()全部执行完成,整个调用栈被清空

如果javascript中定时器(定时器属于宏任务),会将异步程序放进Message Queue消息队列中

案例 2function func1(){
   console.log(1);
};
function func2(){
   setTimeout(()=>{
     console.log(2);	
   },0); 	
   func1();
   console.log(3);
};
func2(); //1 , 3 , 2
**上述代码执行过程
1func2()开始执行,压入到调用栈,开始执行func2内部的代码
2、将setTimeout()压入调用栈时,里面的回调函数会被放进消息队列,消息会在调用栈清空的时候执行;
3、将func1 放入栈,执行输出console.loog(1);执行完成弹出func1;
4、执行完console.log(3)的时候,弹出func2,此时调用栈已经被清空;
5、将消息队列的消息压入到调用栈执行,输出console.log(2),清空栈。

如果使用 async 、 promise 创建的异步操作 会加入到Microtask Queue微任务队列里面, 会在调用栈被清空的时候,立即执行,并且处理期间新加入的微任务也会一起执行

案例 3var p = new Promise(resolve=>{
   console.log(4);
   resolve(5);
});
function func1(){
   console.log(1);
};
function func2(){
   setTimeout(()=>{
   	console.log(2);	
   },0); 	
   func1();
   console.log(3);
   p.then(resolved=>{
   	console.log(resolved)
   }).then(()=>{
   	console.log(6)
   })
};
func2(); // 4, 1, 3, 5, 6, 2
**上述代码执行过程:
1new Promise 构造函数会首先被压入调用栈中,执行console.log(4) 和 resolve(5);
	执行完成后,从栈中弹出 new Promise
2、func2压入栈,将
	setTimeout(()=>{
   	console.log(2);	
   },0);压入栈,并将回调函数放入 消息队列;
3、将func1 压入栈,输出console.log(1);从栈中弹出func1;
4、输出console.log(3)后弹出
5、将promise后面的两个 .then的回调函数会入队到微任务队列里面;
6、func2执行完成,从栈中弹出,此时调用栈已经被清空了
7、将微任务队列中的任务,把他们压入到调用栈分别执行,输入
	console.log(resolved)
	console.log(6)
   执行完之后清空调用栈
8、最后压入并执行消息队列里面的消息console.log(2);
至此,全部执行完成。

本内容纯属学习的时候整理的笔记,如果哪里有问题还请各位大佬务必给出建议和指点