摘要:众所周知和都属于上述异步任务的一种那到底为什么和会有顺序之分这就是我想分析总结的问题所在了和的作用是为了让浏览器能够从内部获取的内容并确保执行栈能够顺序进行。只要执行栈没有其他在执行,在每个结束时,队列就会在回调后处理。
前言
我是在做前端面试题中看到了setTimeout和Promise的比较,然后第一次看到了microtask和macrotask的概念,在阅读了一些文章之后发现没有一个比较全面易懂的文章,所以我尝试做一个梳理性的总结.
这道经典的面试题引起了我的兴趣console.log("script start"); setTimeout(function() { console.log("setTimeout"); }, 0); Promise.resolve().then(function() { console.log("promise1"); }).then(function() { console.log("promise2"); }); console.log("script end");JavaScript的事件循环机制
首先我们先弄清楚setTimeout和Promise的共同点,也就是我第一次的看到那道面试题的疑惑点.
JavaScript 主线程拥有一个 执行栈 以及一个 任务队列,主线程会依次执行代码,当遇到函数时,会先将函数 入栈,函数运行完毕后再将该函数 出栈,直到所有代码执行完毕。
上面的例子的执行栈执行顺序应该是这样的
console.log("script start"); console.log("script end"); Promise.resolve();
而任务队列的执行顺序应该是这样的
Promise.then(function() { console.log("promise1"); }); Promise.then(function() { console.log("promise2"); }); setTimeout(function() { console.log("setTimeout"); }, 0);
而主线程则会在 清空当前执行栈后,按照先入先出的顺序读取任务队列里面的任务。
众所周知setTimeout和Promise.then()都属于上述异步任务的一种,那到底为什么setTimeout和Promise.then()会有顺序之分,这就是我想分析总结的问题所在了.
macrotasks(tasks) 和 microtasks taskstasks的作用是为了让浏览器能够从内部获取javascript / dom的内容并确保执行栈能够顺序进行。
tasks的调度是随处可见的,例如解析HTML,获得鼠标点击的事件回调等等,在这个例子中,我们所迷惑的setTimeout也是一个tasks.
microtasksmicrotasks通常用于在当前正在执行的脚本之后直接发生的事情,比如对一系列的行为做出反应,或者做出一些异步的任务,而不需要新建一个全新的tasks。
只要执行栈没有其他javascript在执行,在每个tasks结束时,microtasks队列就会在回调后处理。在microtasks期间排队的任何其他microtasks将被添加到这个队列的末尾并进行处理。
microtasks包括mutation observer callbacks,就像上例中的promise callbacks一样。
所以上面的例子执行顺序的实质是tasks =>start end以及resolve
microtasks =>promise1和promise2
tasks =>setTimeout
具体应用需要注意的是,在两个tasks之间,浏览器会重新渲染。这也是我们需要了解tasks和microtasks的一个非常重要的原因.
Vue 中如何使用 MutationObserver 做批量处理? - 顾轶灵的回答 - 知乎浏览器兼容问题根据 HTML Standard,在每个 task 运行完以后,UI 都会重渲染,那么在 microtask 中就完成数据更新,当前 task 结束就可以得到最新的 UI 了。反之如果新建一个 task 来做数据更新,那么渲染就会进行两次。
在__Microsoft Edge__, Firefox 40__, __iOS Safari 以及 desktop Safari 8.0.8 中setTimeout会先于Promise
该例子来自Jake Archibald-->Tasks, microtasks, queues and schedules,其中有动画来展现tasks和microtasks的具体工作流程,十分推荐阅读//html
// Let"s get hold of those elements var outer = document.querySelector(".outer"); var inner = document.querySelector(".inner"); // Let"s listen for attribute changes on the // outer element new MutationObserver(function() { console.log("mutate"); }).observe(outer, { attributes: true }); // Here"s a click listener… function onClick() { console.log("click"); setTimeout(function() { console.log("timeout"); }, 0); Promise.resolve().then(function() { console.log("promise"); }); outer.setAttribute("data-random", Math.random()); } // …which we"ll attach to both elements inner.addEventListener("click", onClick); outer.addEventListener("click", onClick);
在这个例子中,不同浏览器的log是不同的,如下所示
Chrome | Firefox | Safari | edge |
---|---|---|---|
click | click | click | click |
promise | mutate | mutate | click |
mutate | click | click | mutate |
click | mutate | mutate | timeout |
promise | timeout | promise | promise |
mutate | promise | promise | timeout |
timeout | promise | timeout | promise |
timeout | timeout | timeout |
事实上Chrome是正确的,而且由此可发现microtasks并不是在tasks的结束阶段开始执行,而是在tasks中回调结束之后(只要没有正在执行的JavaScript代码)
总结tasks会顺序执行,浏览器会在执行间隔重新渲染
microtasks会顺序执行,执行时机为
在没有JavaScript代码执行的callback之后在每一个tasks之后
由于我是前端初学者,对于JavaScript还很不熟悉,对事件循环的进程模型不是很了解,希望这篇文章能够帮助大家.
事件循环机制建议参考文章
阮一峰-->JavaScript 运行机制详解:再谈Event LoopHTML Living Standard — Last Updated 9 April 2018
tasks建议参考文章
Jake Archibald-->Tasks, microtasks, queues and schedules理解 JavaScript 中的 macrotask 和 microtask
setImmediate.js --A YuzuJS production
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/107676.html
摘要:常见应用则是为了完成一些更新应用程序状态的较小的任务,如处理的回调和的修改,以便让这些任务在浏览器重新渲染之前执行。常见应用执行顺序的实现需要至少一个和至少一个。 简介 我们在上一篇 《浅析 JS 中的EventLoop 事件循环》 中提到一个 Event Queue,其实在事件循环中 queue 一共有两种,还有一种叫 Job Queue 其中 Event Queue 在 HTML...
摘要:主线程会暂时存储等异步操作,直接向下执行,当某个异步事件触发时,再通知主线程执行相应的回调函数,通过这种机制,避免了单线程中异步操作耗时对后续任务的影响。 背景 在研究js的异步的实现方式的时候,发现了JavaScript 中的 macrotask 和 microtask 的概念。在查阅了一番资料之后,对其中的执行机制有所了解,下面整理出来,希望可以帮助更多人。 先了解一下js的任务执...
摘要:的回调函数正是处于队列之中。将看做会导致性能问题,回调函数可能会因为渲染等相关产生不必要的延后。浏览器是怎么出错的和在两次点击操作之间运行完成了所有的,就比如的回调函数所展示的,但是似乎有不同的排序算法。 带有可视代码执行顺序的原文链接https://jakearchibald.com/201...,此篇文字并非其完整翻译,加入了一部分自己的理解,比如将其中的task替换为macrot...
摘要:的回调函数正是处于队列之中。将看做会导致性能问题,回调函数可能会因为渲染等相关产生不必要的延后。浏览器是怎么出错的和在两次点击操作之间运行完成了所有的,就比如的回调函数所展示的,但是似乎有不同的排序算法。 带有可视代码执行顺序的原文链接https://jakearchibald.com/201...,此篇文字并非其完整翻译,加入了一部分自己的理解,比如将其中的task替换为macrot...
前言 我在学习浏览器和NodeJS的Event Loop时看了大量的文章,那些文章都写的很好,但是往往是每篇文章有那么几个关键的点,很多篇文章凑在一起综合来看,才可以对这些概念有较为深入的理解。 于是,我在看了大量文章之后,想要写这么一篇博客,不采用官方的描述,结合自己的理解以及示例代码,用最通俗的语言表达出来。希望大家可以通过这篇文章,了解到Event Loop到底是一种什么机制,浏览器和Nod...
阅读 5580·2021-11-24 10:25
阅读 2597·2021-11-16 11:44
阅读 3795·2021-10-11 11:09
阅读 3134·2021-09-02 15:41
阅读 3227·2019-08-30 14:14
阅读 2243·2019-08-29 14:10
阅读 2316·2019-08-29 11:03
阅读 1092·2019-08-26 13:47