其实是通过执行的时机来区分的: 微任务:在本次任务执行完后执行。 宏任务:在下一个任务循环的时候执行。 这里有一张经典的图片,供大家参考: ? 每次事件的循环的执行都是以宏任务开始的。 如果本次宏任务执行完毕了,那么就会检索是否有微任务,如果有,那么就去执行微任务,如果微任务执行完或者没有微任务的话那么就会进入下次事件循环。 本次任务执行完后,检测微任务,发现有2个,一个是第16行的process.nextTick,一个是23行的then,分别执行,打印6和8。 执行下一个宏任务,也就是第3行的setTimeout,分别打印2和4,发现有2个微任务,分别打印3和5。 执行下一个宏任务,也就是第27行的setTimeout,分别打印9和11,发现有2个微任务,分别打印10和12。
//异步任务 }) 宏任务 宏任务主要包括定时器、I/O等等 /* setTimeout setInterval I/O */ 执行优先级 在JS当中,其待执行任务的优先级为同步任务>微任务>宏任务 ,则将其扔到宏任务队列里等待执行。 ,在将微任务队列拿出来执行,首先执行第一个微任务,async1()方法当中的async1 end,再接着执行第二个微任务,Promise.then当中的Promise2,由此,所有的微任务执行完毕,接着开始将宏任务队列拿出来 ,则执行第一个宏任务settimeout当中,打印输出settimeout,由此所有的宏任务处理完毕。 然后在次将微任务、宏任务依次拿出来执行,若是没有,则持续监听,直到有任务。
最近问了大佬一个问题,监听和定时器两个性能的问题,大佬给我普及了宏任务和微任务的概念,于是网上找见了这样一段代码: console.log('script start'); setTimeout(function Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2' 的执行机制,JavaScript的事件循环、同步、异步就不多说了,今天分享的是宏任务和微任务。 先记住两个概念: 宿主环境提供的叫宏任务,由语言标准提供的叫微任务,这是算比较标准也算比较好记忆的区分宏任务和微任务了。 宿主环境内所有的内建或自定义的变量/函数都是 global/window 这个全局对象的属性/方法,而由宿主环境提供的也叫宏任务。
JavaScript中有哪些宏任务与微任务呢? 事件循环的顺序,决定js代码的执行顺序进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。 然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务console.log(1);setTimeout(function() { console.log(2)},1000);new 因为以同步异步的方式来解释执行机制是不准确的,更加准确的方式是宏任务和微任务: 因此执行机制便为:执行宏任务 ===> 执行微任务 ===> 执行另一个宏任务 ===> 不断循环 即 :在一个事件循环中,执行第一个宏任务,宏任务执行结束,执行当前事件循环中的微任务,执行完毕之后进入下一个事件循环中,或者说执行下一个宏任务*/【小结】接触了宏任务与微任务后,可以帮助更好地理解同步与异步任务
同步任务 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务; const num1 = 1; const num2 = 2; const num3 = 3; console.log 宏任务、微任务 实际上异步任务之间并不相同,因此他们之间也有优先级之分,所以任务队列被分成两种类型: 宏任务和微任务。 ,然后检查"任务队列"中是否有任务,如果有,就将第一个事件对应的回调,推到执行栈中执行; ==注意:==异步任务分宏任务和微任务两种类型,微任务比宏任务的执行时间要早,所以会优先把所有的微任务放到执行栈中执行 在执行任何一个宏任务以前(不是队列,是一个宏任务),都会查看微任务队列是否有任务需要清空,也就是宏任务执行以前,必须保证微任务是空的。 所以从上面的代码例子中可以得出: 先把同步任务执行,得到 1,5, 然后依次执行微任务(Promise),得到 2, 4,最后执行宏任务(setTimeout),得到3, 7。
微任务、宏任务与Event-Loop 首先,JavaScript是一个单线程的脚本语言。 而且一个宏任务在执行的过程中,是可以添加一些微任务的,就像在柜台办理业务,你前边的一位老大爷可能在存款,在存款这个业务办理完以后,柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“最近P2P 在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。 所以就得到了上述的输出结论1、2、3、4。 (结束本次宏任务、检查还有没有宏任务需要处理) 这个检查的过程是持续进行的,每完成一个任务都会进行一次,而这样的操作就被称为Event Loop。 ) } // 添加一个宏任务 if (macroIndex === 2) macroTaskList.push(['special macro task']) } // > task1
JS 中的异步任务分为宏任务 (macro task) 和微任务 (micro task) ,只有宏任务会进行事件循环。 事件循环 JS 是单线程执行的,所有 JS 代码都要放在主线程中运行。 因此,在同一次循环中,微任务比宏任务优先执行;在整个执行过程中,微任务复用一个队列,而宏任务共用一个队列。 微任务和宏任务的执行顺序 在同一次循环中,微任务比宏任务优先执行,任务按照推入队列的顺序执行(FIFO)。 在处理微任务和宏任务互相包含的情况,记住两点: 微任务不参与事件循环,微任务会被推到当前循环对应的微任务队列中,即使是微任务中的微任务。 宏任务将开启新的事件循环。 下面几道题: Tick: (h1, h2(w1, w2), w3) Tick: (w1(w2(w3)), w4) Tick: (w1(h1(w2)), w3(w4)) h 表示宏任务,w 表示微任务,求解运行顺序
宏任务队列1的任务2 }).then(() => {//宏任务队列1中的微任务 console.log('4') }) }, 0) setTimeout(() => {//宏任务队列 2 console.log('5') }, 0) console.log('6')//同步主线程 执行整体代码(宏任务)console.log('6') >> 宏任务队列1、宏任务队列2位异步(依次执行 剩下的不会先执行,因为是宏任务中的宏任务(console.log(2)) ,要被继续丢进任务队列后 宏任务队列2:=> console.log('5') 宏任务队列1中的宏任务3 2:console.log(3) 宏任务队列1中的微任务:console.log(4) 宏任务队列3:因他是宏任务队列1中的宏任务,所以被丢进了任务队列最后,我们先看宏任务队列 宏任务队列2 console.log(5) 所以输出的结果是什么?是6,1,3,4,5,2! 经过验证,结果正确!
事件轮询中的宏任务和微任务。 那么,你能说清楚到底宏任务和微任务是什么?是谁发起的?为什么微任务的执行要先于宏任务呢? 首先,我们需要先知道JS运行机制。 概念5:宏任务和微任务 ES6 规范中,microtask 称为 jobs,macrotask 称为 task 宏任务是由宿主发起的,而微任务由JavaScript自身发起。 所以,总结一下,两者区别为: 宏任务(macrotask) 微任务(microtask) 谁发起的 宿主(Node、浏览器) JS引擎 具体事件 1. script (可以理解为外层同步代码)2. setTimeout 因为微任务优先级太高,Vue 2.4版本之后,提供了强制使用宏任务的方法。 vm.$nextTick优先使用Promise,创建微任务。
2. 微任务、宏任务概念介绍微任务与宏任务就属于js代码的范畴js代码主要分为两大类: 同步代码、异步代码异步代码又分为:微任务与宏任务图片3. 事件循环Event Loop执行机制1.进入到script标签,就进入到了第一次事件循环.2.遇到同步代码,立即执行3.遇到宏任务,放入到宏任务队列里.4.遇到微任务,放入到微任务队列里.5.执行完所有同步代码 执行Promise的then方法里的代码,打印63.微任务执行完毕后,最后执行定时器里的宏任务,打印2,3,4三.图片参考 前端进阶面试题详细解答1.先执行主线程上的同步代码,打印12.执行第9行的函数 ,进⼊async1内部,async1其实是声明了⼀个promise,promise是同步代码,会顺序执⾏打印async2函数里的4 ,只有.then⾥⾯的代码会加⼊微任务队列⾥,这⾥相当于执⾏了async2 ⾏微任务队列内的任务,遵循先进先出的原则,打印第四⾏的2。
加入微任务,遇到 timeout2,加入宏任务。 输出script end 宏任务第一个执行结束 当前任务队列:微任务[then1],宏任务[timeou1, timeout2] 微任务: 执行 then1,输出then1 微任务队列清空 当前任务队列 :微任务[],宏任务[timeou1, timeout2] 宏任务: 输出timeout1 输出timeout2 当前任务队列:微任务[],宏任务[timeou2] 微任务: 为空跳过 当前任务队列:微任务 [],宏任务[timeou2] 宏任务: 输出timeout2 #async/await 的执行 async 和 await 其实就是 Generator 和 Promise 的语法糖。 ],宏任务[timeout] 微任务: 输出:promise2 promise2 出队 输出:async1 end async1 end 出队 微任务队列清空 当前任务队列:微任务[],宏任务[timeout
前端高频面试题: 宏任务(macro-task)与微任务(micro-task) 01 概念理解 宏任务和微任务都是我们在开发工作中经常用到的。 微任务主要是:Promise、Object.observe、MutationObserver。 宏任务和微任务之间的关系 宏任务和微任务的区别 宏任务 1. 宏任务所处的队列就是宏任务队列 2. 宏任务队列可以有多个 3. 当宏任务队列的中的任务全部执行完以后会查看是否有微任务队列如果有先执行微任务队列中的所有任务,如果没有就查看是否有宏任务队列 微任务 1. 微任务所处的队列就是微任务队列 2. 在上一个宏任务队列执行完毕后如果有微任务队列就会执行微任务队列中的所有任务 总结: 首先浏览器执行js进入主线程, 然后再判断是否有微任务,有就执行; 再判断是否有宏任务,有进行执行,执行后,再判断是否有微任务
在宏任务执行过程中,v8引擎都会建立新栈存储任务,宏任务中执行不同的函数调用,栈随执行变化,当该宏任务执行结束时,会清空当前的栈,接着主线程继续执行下一个宏任务。 而无论是宏任务还是微任务依赖的都是基础的执行栈和消息队列的机制而运行。根据定义,宏任务和微任务存在于不同的任务队列,而微任务的任务队列应该在宏任务执行栈完成前清空。 此时当前已没有主逻辑执行的代码,而当前宏任务将执行结束,微任务会在当前宏任务完成前执行,所以微任务队列会依次执行,直到微任务队列清空。 从一开始浏览器端就是严格遵循了微任务和宏任务定义进行执行,也就是说,一个宏任务执行完成过程中,就会去检测微任务队列是否有需要执行的任务,即使是微任务嵌套微任务,也会将微任务执行完成,再去执行下一个宏任务 微任务嵌套微任务可能造成线程中一直处于当前微任务队列执行状态而走不下去,而宏任务的嵌套循环执行,并不会造成内存溢出的问题,因为每个宏任务的执行都是新建的栈。
最后,我们将一个繁重的任务拆分成了几部分,现在它不会阻塞用户界面了。而且其总耗时并不会长很多。 用例 2:进度指示 对浏览器脚本中的过载型任务进行拆分的另一个好处是,我们可以显示进度指示。 除了本章中所讲的 宏任务(macrotask) 外,还有在 微任务队列[2] 一章中提到的 微任务(microtask)。 每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或渲染,或进行其他任何操作。 执行所有 微任务: 出队(dequeue)并执行最早的微任务。 当微任务队列非空时: 执行渲染,如果有。 如果宏任务队列为空,则休眠直到出现宏任务。 转到步骤 1。 ---- 参考资料 [1]创建自定义事件: https://zh.javascript.info/dispatch-events [2]微任务队列: https://zh.javascript.info
async function async1() { console.log("async1 start"); //2 await async2(); console.log("async1 end"); // 6 } async function async2() { console.log("async2"); // 3 } console.log("script start" resolve) { console.log("promise1"); // 4 resolve(); }).then(function () { console.log("promise2" ); // 7 }); console.log("script end"); // 5 script start async1 start async2 promise1 script end async1 end promise2 setTimeout
在介绍宏任务和微任务之前,先抛出一个问题。 then(function(){undefined console.log(‘3’) }); console.log(‘4’); 请说出控制台打印的数据,很多小伙伴经过深思熟虑之后,会自信的说出答案:2、 但是事情并不是那么的简单,接下来引入两个新概念:宏任务(macrotask)和微任务(microtask) 宏任务(macrotask)和微任务(microtask) 宏任务和微任务表示的是异步任务的两种分类 然后首先会从宏任务的任务队列中中取出一条任务执行;当执行完毕之后再将微任务队列里面的所有的任务按照顺序执行;当所有的微任务队列任务执行完毕之后,再去宏任务队列中取出一条任务执行。 那么宏任务和微任务到底是什么关系呢?
image.png 不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务(microtask) 和 宏任务(macrotask)。 所以 Event Loop 执行顺序如下所示: 首先执行同步代码,这属于宏任务 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行 执行所有微任务 当执行完所有微任务后,如有必要会渲染页面 setTimeout 属于宏任务,所以会有以上的打印。 宏任务包括 script , setTimeout ,setInterval ,setImmediate ,I/O ,UI rendering 。 这里很多人会有个误区,认为微任务快于宏任务,其实是错误的。因为宏任务中包括了 script ,浏览器会先执行一个宏任务,接下来有异步代码的话才会先执行微任务。
,又把任务队列中的异步任务分为宏任务和微任务,虽然他们都在任务队列中,但是它们却在不同的队列中,微任务的执行优先级大于宏任务,他们的结构如图所示。 宏任务 浏览器为了能够使得JS内部任务与DOM任务能够有序的执行,会在一个任务执行结束后,在下一个任务执行开始前,对页面进行重新渲染 常见的宏任务主要有 定时器,ajax,读取文件,dom事件,setImmediate setTimeout qz"); }, 0); console.log("qz"); //输出结果 //qz //setTimeout qz 2.先执行主线程的同步任务,构造函数是同步任务 ,打印.then,bbb,此时微任务没了,开始执行宏任务,打印定时器,因为定时器中含有微任务和宏任务,所以继续打印ccc,再执行定时器中的宏任务ddd,最后打印eee Promise.resolve() 2.同时,主线程执行中遇到异步任务,会将其推给异步进程进行处理,webAPI 3.异步任务对异步任务进行处理,遵循先进先出的顺序依次推入任务队列(异步队列) 4.主线程执行完同步队列之后,查询任务队列
2. 微任务、宏任务概念介绍微任务与宏任务就属于js代码的范畴js代码主要分为两大类: 同步代码、异步代码异步代码又分为:微任务与宏任务图片3. 事件循环Event Loop执行机制1.进入到script标签,就进入到了第一次事件循环.2.遇到同步代码,立即执行3.遇到宏任务,放入到宏任务队列里.4.遇到微任务,放入到微任务队列里.5.执行完所有同步代码 执行Promise的then方法里的代码,打印63.微任务执行完毕后,最后执行定时器里的宏任务,打印2,3,4三.图片1.先执行主线程上的同步代码,打印12.执行第9行的函数,进⼊async1内部,async1 2. 微任务、宏任务概念介绍微任务与宏任务就属于js代码的范畴js代码主要分为两大类: 同步代码、异步代码异步代码又分为:微任务与宏任务图片3. 事件循环Event Loop执行机制1.进入到script标签,就进入到了第一次事件循环.2.遇到同步代码,立即执行3.遇到宏任务,放入到宏任务队列里.4.遇到微任务,放入到微任务队列里.5.执行完所有同步代码
宏任务(MacroTask)引入 在 JS 中,大部分的任务都是在主线程上执行,常见的任务有: 渲染事件 用户交互事件 js脚本执行 网络请求、文件读写完成事件等等。 上述提到的,普通任务队列和延迟队列中的任务,都属于宏任务。 微任务(MicroTask)引入 对于每个宏任务而言,其内部都有一个微任务队列。那为什么要引入微任务?微任务在什么时候执行呢? 其实引入微任务的初衷是为了解决异步回调的问题。想一想,对于异步回调的处理,有多少种方式?总结起来有两点: 将异步回调进行宏任务队列的入队操作。 将异步回调放到当前宏任务的末尾。 在每一个宏任务中定义一个微任务队列,当该宏任务执行完成,会检查其中的微任务队列,如果为空则直接执行下一个宏任务,如果不为空,则依次执行微任务,执行完成才去执行下一个宏任务。 Ok, 这便是宏任务和微任务的概念,接下来正式介绍JS非常重要的运行机制——EventLoop。