事件循环和任务队列

如有错误欢迎指正,谢~

我们都知道js是单线程语言,也就是只有一个线程,常称为主线程,在该线程中包含任务队列和执行栈

任务队列:

一些异步操作会将相关回调添加到任务队列中,而且不同的异步操作添加到队列的时间也不一样。

eg:

①onclick 等异步是当事件触发立即会将回调放到任务队列中。

②settimeout 会等到延迟时间到了再把回调放到任务队列中。

③像网络请求ajax是等到请求完成的时候再把回调放到任务队列中去。

执行栈:

执行栈就相当于一个全局方法,主方法,里面有个同步任务和异步任务,主线程在执行碰到同步任务就执行,碰到异步任务就将其回调放到任务队列中,执行完同步任务之后,就开始执行任务队列了,有一点要知道:

①一个事件循环中有一个或多个任务队列。

②每个事件循环都有一个microtask队列。

③macrotask队列就是我们常说的任务队列,microtask队列不是任务队列

④一个任务可以被放入到macrotask队列,也可以放入microtask队列

具体怎么划分看下面:

macrotasks(就是我们平常说的任务队列)和microtasks的划分:

macrotasks包括:setTimeout,setInterval,setInterval,setImmediate,requestAnimationFrame,I/O,UI rendering

microtasks包括:process.nextTick,Promises,Object.observe,MutationObserver

那么在执行队列(macrotasks队列==任务队列和microtasks队列)的时候,是怎样执行的呢?

microtask执行会在以下两种情况:

①任务队列(macrotask ==任务对列)回调后执行,前提条件是当前没有其他执行中的代码。

②每个任务队列(macrotask ==任务对列)末尾执行。

另外在处理microtask期间,如果有新添加的microtasks,也会被添加到队列的末尾并执行。

可以总结执行顺序如下:

开始 ----->取任务队列第一个task执行 ----->取microtask全部任务依次执行 ----->取任务队列下一个任务执行----->再次取出microtask全部任务执行-----> 。。。这样循环往复

伪代码大概表示了这个过程:

 1 //js的任务队列和执行栈  
 2 let queue=[];
 3 let mircqueue=[];
 4 function Main(){//浏览器js主线程
 5       let event;
 6       function executeStack(){//执行栈
 7          ..............;//执行栈中执行的同步代码 碰到宏观任务将回调放到任务队列中 下一次循环会执行
 8          //执行完可执行的任务之后,立即执行微观任务,如下:
 9          for(var i=0;i<mircqueue.length;i++){//取出所有microtask执行
10             event=queue.shift();//取出任务队列一个任务
11             event();//执行
12          }         
13          while(true){//事件循环
14              if(queue.length>0){
15                 event=queue.shift();//取出任务队列一个任务
16                 event();执行
17              }
18              if(mircqueue.length>0){
19                 for(var i=0;i<mircqueue.length;i++){//取出所有microtask执行
20                     event=queue.shift();//取出任务队列一个任务
21                     event();//执行
22                  }     
23              }
24                      
25          }
26      }
27  }
28  
29  function Other(){//浏览器其他的线程
30      function onxxx(){
31         queue.push(new Task());//浏览器线程往任务队列中添加回调事件 
32         //或者
33         mircqueue.push(new Task());//浏览器线程往microtask中添加回调事件    
34   }
35  }
36  Main();
37  Other();

那么我们来看一个例子:

eg1:

 1 setTimeout(function(){
 2     console.log(1)
 3 },0);
 4 new Promise(function(resolve){
 5     console.log(2)
 6     for( var i=100000 ; i>0 ; i-- ){
 7         i==1 && resolve()
 8     }
 9     console.log(3)
10 }).then(function(){
11     console.log(4)
12 });
13 console.log(5);

结果是

2

3

5

4

1

eg2:

 1 setTimeout(function(){
 2     console.log(1)
 3 },0);
 4 setTimeout(function(){
 5     console.log(6)
 6 },2000);
 7 new Promise(function(resolve){
 8     console.log(2)
 9     for( var i=100000 ; i>0 ; i-- ){
10         i==1 && resolve()
11     }
12     console.log(3)
13 }).then(function(){
14     console.log(4);
15     setTimeout(function(){
16         console.log(8)
17     },1000)
18 });
19 console.log(5);

这个执行结果是啥呢???想想

结果是:

2
3
5
4
1
8
6

总结一下,便于自己学习,也分享大家一起学习。(#^.^#)

猜你喜欢

转载自www.cnblogs.com/zhanghaiyu-Jade/p/11123762.html