事件循环和任务队列

Posted zhanghaiyu-jade

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事件循环和任务队列相关的知识,希望对你有一定的参考价值。

如有错误欢迎指正,谢~

我们都知道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

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

以上是关于事件循环和任务队列的主要内容,如果未能解决你的问题,请参考以下文章

事件循环和任务队列

JS-线程事件循环任务队列

JS-线程事件循环任务队列

详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务

浏览器视角看——消息队列和事件循环(EventLoop)宏任务和微任务

消息队列和事件循环