事件循环和任务队列

如有错误欢迎指正,谢~

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

任务队列:

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

eg:

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

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

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

 

执行栈:

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

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

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

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

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

具体怎么划分看下面:

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

macrotasks包括:script (整体代码),setTimeout,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

 

 eg3:

setImmediate(function(){
  console.log(1);
},0);
setTimeout(function(){
  console.log(2);
},0);
new Promise(function(resolve){
  console.log(3);
  resolve();
  console.log(4);
}).then(function(){
  console.log(5);
});
console.log(6);
process.nextTick(function(){
  console.log(7);
});
console.log(8);

node 环境下:

3,4,6,8,5,1,2,7

浏览器环境下:

settimeout  优先级大于 setImmediate

nextTick 优先级 大于 promise

3,4,6,8,7,5,2,1

 eg4:

//加入两个nextTick的回调函数
process.nextTick(function () {
  console.log('nextTick延迟执行1');
});
process.nextTick(function () { 
  console.log('nextTick延迟执行2');
});
// 加入两个setImmediate()的回调函数
setImmediate(function () {
  console.log('setImmediate延迟执行1'); 
  // 进入下次循环 
  process.nextTick(function () {
    console.log('强势插入');
  });
});
setImmediate(function () {
  console.log('setImmediate延迟执行2'); 
});
 
console.log('正常执行');

node 环境下:正常执行,setImmediate延迟执行1,setImmediate延迟执行2,nextTick延迟执行1,nextTick延迟执行2,强势插入

浏览器环境下:正常执行,nextTick延迟执行1,nextTick延迟执行2,setImmediate延迟执行1,强势插入,setImmediate延迟执行2

 

 

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

转载于:https://www.cnblogs.com/zhanghaiyu-Jade/p/11123762.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值