JS微队列和宏队列

我们都知道js是单线程,它的语言是通过浏览器内核多线程实现异的,

浏览器的进程其中《渲染进程》有:

  • GUI线程:渲染布局,解析css,html,构建dom树,渲染树
  • JS引擎线程:解析、执行js代码块,与GUI线程互斥。因为js同样可以修改,html,css,布局等,同时使用有可能产生页面混乱。
  • 定时触发线程:处理setTimeout,setInterval
  • 事件触发线程:将满足触发条件的事件放入任务队列
  • 异步HTTP请求线程:XHR所在的线程

多线程实现异步会放入(入栈)到主线程Event Loop遍历任务队列执行(出栈),不同的浏览器厂商有不同的Event Loop 实现

宏队列和微队列

宏队列,macrotask,也叫tasks.一些异步任务的回调会依次进入 macro task queue,等待后渎被调用,这些异步任务包括:

  • setTimeout
  • setInterval
  • setImmediate(Node独有)
  • requestAnimationFrame(浏览器独有)
  • I/O
  • UI rendering(浏览器独有)

微队列,microtask,也叫jobs。另一些异步任务的回调会依次进入micro task queue,等待后渎被调用,这些异步任务包括:

  • process.nextTick(Node独有)
  • Promise
  • Object.observe
  • MutationObserver

(注:这里只针对浏览器和NodeJS)

Javascriot代码的具体流程:

  1. 执行全局Script代码
  2. 全局Script代码执行完毕后,调用栈Stack会清空
  3. 然后从微队列microtask queue中取出位于队首的回调任务,放入调用栈Stack中执行,执行完后microtask queue长度减1
  4. 如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行
  5. 直到microtask queue中所有任务都执行完毕,此时microtask queue为空队列,调用栈Stack也为空
  6. 然后再取出宏队列macrotask queue中位于队首的任务,放入Stack中执行
  7. 执行完毕后,调用栈Stack为空
  8. 重复第3-7个步骤
  9. ......

这就是浏览器的事件循环Event Loop

这里归纳3个重点:

  1. 宏队列macrotask一次只从队列中取一个任务执行,执行完后就去执行微任务队列中的任务
  2. 微任务队列中所有的任务都会被依次取出来执行,知道microtask queue为空
  3. 只要执行UI rendering,它的节点是在执行所有的microtask之后,下一个macrotask之前,紧跟着执行UI render

巩固测试一下:

console.log(1);

setTimeout(()=>{
    console.log(2);
    Promise.resolve().then(()=>{
        console.log(3);
    })
})

new Promise((resolve,reject)=>{
    console.log(4);
    resolve(5)
}).then((data)=>{
    console.log(data);    
})

setTimeout(()=>{
    console.log(6);    
})

console.log(7);
// 输出的结果
1
4
7
5
2
6
3

分析流程:

Step1:

console.log(1)

Stack queue:[console]

mircotask queue:[]

marcotask queue:[]

此时打印结果:

1

 Step2:

setTimeout(()=>{
    console.log(2); // callback1
    Promise.resolve().then(()=>{
        console.log(3); // callback4
    })
})

setTimeout 是宏任务,所以要放入marcotask queue队列

Stack queue:[]

mircotask queue:[]

marcotask queue:[callback1]

此时打印结果:

1

Step3: 

new Promise((resolve,reject)=>{
    console.log(4);
    resolve(5)
}).then((data)=>{
    console.log(data);    // callback2
})

promise里console.log(4),是同步执行,也就是放入到Stack queue,.then是微任务放入mircotask queue

Stack queue:[console]

mircotask queue:[callback2]

marcotask queue:[callback1]

此时打印结果:

1、4 

Step4: 

setTimeout(()=>{
    console.log(6);    // callback3
})

setTimeout 是宏任务,放入到marcotask queue

Stack queue:[]

mircotask queue:[callback2]

marcotask queue:[callback1,callback3]

此时打印结果:

1、4

Step5: 

console.log(7); // console

Stack queue:[console]

mircotask queue:[callback2]

marcotask queue:[callback1,callback3]

此时打印结果:

1、4、7

  • 好啦,全局Script的代码执行完了,进入下一个步骤,从mircotask queue微任务队列里从队首依次取出执行,直到mircotask queue为空

Step6: 

Stack queue:[]

mircotask queue:[callback2]

marcotask queue:[callback1,callback3]

此时打印结果:

1、4、7、5

Step7: 

  • 这里mircotask queue只有一个任务执行完后,就去marcotask queue宏任务队列,队首取出执行

Stack queue:[]

mircotask queue:[]

marcotask queue:[callback1,callback3]

此时打印结果:

1、4、7、5、2

Step8: 

  • marcotask 需要注意的是,每一个任务执行完后会先检查Stack queue和mircotask queue里是否有新任务,如果有就执行,没有就依次队首取出执行
  • 这里setTimeout 输出结果2后,先检查没有其他队列任务后就继续执行 ,发现promise.then是微任务,就放入到mircotask queue微队列里,同时也执行下一个marcotask队首任务

Stack queue:[]

mircotask queue:[callback4]

marcotask queue:[callback3]

此时打印结果:

1、4、7、5、2、6

Step9: 

  • 这里宏任务队首执行完后,检查mircotask queue里有一个任务,就开始执行mircotask 队首任务

Stack queue:[]

mircotask queue:[callback4]

marcotask queue:[]

此时打印结果:

1、4、7、5、2、6、3

  • 当mircotask任务执行完后,去检查是否有其他任务要执行,这里发现Stack queue:[],mircotask queue:[],marcotask queue:[]都是空的,结束。

 

 

 

摘自:

《理解异步》

https://note.youdao.com/ynoteshare1/index.html?id=0f6e7a2a2ab18a59971569fe5650c113&type=note

《弄懂Event Loop》

https://segmentfault.com/a/1190000016278115

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
任务和任务是在JavaScript中用于管理异步操作的两种不同的执行机制。 任务(Microtask)是一个相对较小的任务,通常是由Promise对象的回调函数产生的。当一个Promise对象被resolve或reject时,与该Promise相关联的任务会被添加到任务队列中等待执行。任务的执行时机一般在当前任务执行结束后,下一个事件循环之前。常见的任务包括Promise的回调函数、MutationObserver的回调函数等。 任务(Macrotask)是一个相对较大的任务,通常由浏览器提供的API触发,例如setTimeout、setInterval、requestAnimationFrame等。当任务被触发时,相关的任务会被添加到任务队列中等待执行。任务的执行时机一般在当前事件循环结束后,下一个事件循环开始时。 区别总结如下: - 任务是相对较小的任务,任务是相对较大的任务。 - 任务的执行时机在当前任务执行结束后,下一个事件循环之前;任务的执行时机在当前事件循环结束后,下一个事件循环开始时。 - 任务的优先级高于任务,即任务会在任务之前执行。 - 任务包括Promise的回调函数、MutationObserver的回调函数等;任务包括setTimeout、setInterval、requestAnimationFrame等。 需要注意的是,任务和任务的执行顺序是有区别的,具体执行顺序可以参考相关规范(例如HTML规范或JavaScript规范),不同浏览器也可能有差异。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值