JS微任务和宏任务(⾯试题常⽤)
单线程和任务队列
1. 单线程就意味着,所有任务需要排队,前⼀个任务结束,才会执⾏后⼀个任务。如果前⼀个任务耗时很长,后⼀个任务就不得不⼀直
等待。
2. 如果排队是因为计算量过⼤,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输⼊输出设备)很慢(⽐如Ajax操
作从⽹络读取数据),不得不等着结果出来,再往下执⾏!
3. JavaScript语⾔的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运⾏排在后边的任务,等到IO设备返
回了结果,再回过头把挂起的任务继续执⾏下去
4. 于是,所有的任务可以分为两种,⼀种是同步任务(synchronous),另外⼀种是异步任务(asynchronous)。同步任务指的是,在
主线程上,排队执⾏的任务,只有前⼀个任务执⾏完毕,才能执⾏后⼀个任务;异步任务指的是,不进⼊主线程,⽽进⼊“任务队列”(task queue)的任务,只有“任务队列”通知主线程,某个异步任务可以执⾏了,该任务才会进⼊主线程执⾏。
javascript事件循环
原生js和js的区别
1. 同步任务:直接通过主线程执⾏,如script代码
2. 异步任务: 进⼊Event Table,并注册回调函数——> Event Queue,等主线程的执⾏栈为空时候,读取Event Queue⾥⾯的函数就,
进⼊主线程。如setTimeout,promise.then()等;
javascript是单线程的,但是浏览器是多线程的,典型的浏览器有如下线程:
javascript引擎线程
界⾯渲染线程
浏览器事件触发线程
Http请求线程
关于javaScript的单线程
应⽤场景决定了javascript的单线程的特性,假如javascript是多线程,同时进⾏:⼀个线程对某⼀个dom进⾏添加属性操作,另⼀个线程对该线程进⾏删除操作,那么浏览器该听哪⼀个。这就决定javascript必须是单线程。
web worker:是⼀个多线程。它出现的⽬的是当浏览器有⼤量密集的计算时候或者响应时间很长的运算时候,页⾯出现卡顿,可以起⼀个worker⼦线程,主线程和worker线程互不⼲预,这样页⾯就可以进⾏点击之类的操作,但这个⼦线程不能操作DOM元素。
任务队列
Js 中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(microtasks)。宏任务队列可以有多个,微任务队列只有⼀个
宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering.
微任务:Tick (node.js中进程相关的对象), Promise, Object.observer, MutationObserver。
宏任务(macrotask )和微任务(microtask )
macrotask 和 microtask 表⽰异步任务的两种分类。
宏任务(task):就是JS 内部(任务队列⾥)的任务,严格按照时间顺序压栈和执⾏。如 setTimeOut、setInverter、setImmediate 、MessageChannel等
微任务(Microtask ):通常来说就是需要在当前 任务 执⾏结束后⽴即执⾏的任务,例如需要对⼀系列的任务做出回应,或者是需要异步的执⾏任务⽽⼜不需要分配⼀个新的 任务 ,这样便可以减⼩⼀点性能的开销。
在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,⾸先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第⼀个任务,执⾏完毕后取出 microtask 队列中的所有任务顺序执⾏;之后再取 macrotask 任务,周⽽复始,直⾄两个队列的任务都取完。
宏任务与微任务的关系:
宏任务与微任务属性机制:
运⾏机制:
1. 在执⾏栈中执⾏⼀个宏任务。
2. 执⾏过程中遇到微任务,将微任务添加到微任务队列中。
3. 当前宏任务执⾏完毕,⽴即执⾏微任务队列中的任务。
4. 当前微任务队列中的任务执⾏完毕,检查渲染,GUI线程接管渲染。
5. 渲染完毕后,js线程接管,开启下⼀次事件循环,执⾏下⼀次宏任务(事件队列中取)。让我们先来看⼀段代码:
1. ⾸先浏览器执⾏js进⼊第⼀个宏任务进⼊主线程, 直接打印console.log(‘1’)
2. 遇到 setTimeout 分发到宏任务Event Queue中
3. 遇到 Tick 丢到微任务Event Queue中
4. 遇到 Promise, new Promise 直接执⾏ 输出 console.log(‘7’);
5. 执⾏then 被分发到微任务Event Queue中``
6. 第⼀轮宏任务执⾏结束,开始执⾏微任务 打印 6,8
7. 第⼀轮微任务执⾏完毕,执⾏第⼆轮宏事件,执⾏setTimeout
8. 先执⾏主线程宏任务,在执⾏微任务,打印’2,4,3,5’
9. 在执⾏第⼆个setTimeout,同理打印 ‘9,11,10,12’
10. 整段代码,共进⾏了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。
以上是在浏览器环境下执⾏的数据,只作为宏任务和微任务的分析,我在node环境下测试打印出来的顺序为:
1,7,6,8,2,4,9,11,3,10,5,12。node环境执⾏结果和浏览器执⾏结果不⼀致的原因是:浏览器的Event loop是在HTML5中定义的规范,⽽node中则由libuv库实现。libuv库流程⼤体分为6个阶段:timers,I/O callbacks,idle、
prepare,poll,check,close callbacks,和浏览器的microtask,macrotask那⼀套有区别。
注意事项:
1. 先是宏任务–>微任务–>宏任务–>微任务⼀直循环下去;
2. script代码为第⼀层宏任务,如果有setTimeout,setInterval,则他们的回调函数会成为第⼆层的宏任务,
3. promise.then()和Tick()是微任务,在执⾏完该⼀层的宏任务后执⾏,且Tick()优先于promise.then();⼩结
1. macrotask(按优先级顺序排列): script(你的全部JS代码,“同步代码”), setTimeout, setInterval, setImmediate, I/O,UI
rendering
2. microtask(按优先级顺序排列):Tick,Promises(这⾥指浏览器原⽣实现的 Promise), Object.observe,
MutationObserver
3. JS引擎⾸先从macrotask queue中取出第⼀个任务,执⾏完毕后,将microtask queue中的所有任务取出,按顺序全部执⾏;
4. 然后再从macrotask queue(宏任务队列)中取下⼀个,执⾏完毕后,再次将microtask queue(微任务队列)中的全部取出;
5. 循环往复,直到两个queue中的任务都取完。
提别强调:
队列的优先级执⾏顺序为: 先执⾏同步和⽴即执⾏任务>microtask>macrotask

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。