浅谈javascript事件环微任务和宏任务队列原理

 更新时间:2020年09月12日 14:36:04   作者:木瓜太香  
这篇文章主要介绍了javascript事件环 微任务和宏任务队列原理,帮助大家更好的理解和学习JavaScript,感兴趣的朋友可以了解下

JS 事件环

JS 程序的运行是离不开事件环机制的,这个机制保证在发生某些事情的时候我们有机会执行一个我们事先预定好的函数,事情发生的时候 JS 会将相应的函数入栈执行然后出栈,但是关于事件环我们还有一些未知的东西,例如,setTimeout 我们习惯称他为定时器,但是可能很多人没有意识到,这个东西和我们常用的一些事件没什么不同,只不过我们通常所说的事件大多需要用户触发,而 setTimeout 不用用户自己触发,而是指定时间之后触发;那么问题来了,如果我们将时间设置为 0 会发生什么?会立即执行么?

setTimeout、DOM或者 HTTP请求这部分其实并不在 v8 引擎中,这些属于 web API,javascript 是一个单线程的语言,也就意味着一次只能做一件事情,这个事实从未改变

执行原理

JS 中所有的方法都会被推入栈中执行,执行完成被弹出,在遇到异步代码的时候,例如 setTimeout MutationObserver Promise 异步的部分会由其他掌管 webAPI 的地方执行,等异步有结果之后,回调函数会进入相应的队列,Promise MutationObserver 回调进入微任务队列,setTimeout setInterval requestAnimationFrame 进入宏任务队列。等待主线程的执行栈空了,微任务队列立刻被推入栈中执行,执行完毕开始执行宏任务队列

一个经典的例子

html

<div class="outer">
 <div class="inner"></div>
</div>

js

// 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);

以上代码在,手动点击 inner 元素的时候会有如下输出

click
promise
mutate
click
promise
mutate
timeout
timeout

截止 2020年8月份 chrome edge opera firefox 的结果是统一的,但是在此之前的版本可能会有不同的输出。

一个奇怪的现象

上述代码我们不使用手动触发点击,而是使用 inner.click() 触发点击,其结果会有很大的不同

click
click
promise
mutate
promise
timeout
timeout

造成以上巨大差异的原因是,手动点击,不是通过函数进入执行栈的方式触发点击事件的回调,所以inner 的回调执行完了主线程中的执行栈就是空的可以直接执行队列中任务,然后事件冒泡导致的回调函数才被推入栈运行;而 click 方法的点击则是通过将 click 推入栈中执行来达到的,inner 的点击回调执行完了之后 click 方法并没有被弹出栈,而是直接执行冒泡的下一个回调,由于下一个回调有一个重复的 属性设置 这是不会重复触发 MutationObserver的所以 mutate 的输出只会有一个。等所有的冒泡回调被执行完毕 click 函数才会被弹出栈。

最后注意,浏览器会尽量预先执行较为敏感的操作。

以上就是浅谈javascript事件环微任务和宏任务队列原理的详细内容,更多关于JavaScript 事件环的资料请关注脚本之家其它相关文章!

相关文章

  • javascript制作的cookie封装及使用指南

    javascript制作的cookie封装及使用指南

    这篇文章主要介绍了javascript制作的cookie封装及使用指南,需要的朋友可以参考下
    2015-01-01
  • 基于JS实现移动端左滑删除功能

    基于JS实现移动端左滑删除功能

    最近做个项目,需要实现移动端左滑删除功能,当时js代码将网上找的进行删减优化,下面通过本文给大家分享基于JS实现移动端左滑删除功能,感兴趣的朋友一起看看
    2017-07-07
  • javascript中数组和字符串的方法对比

    javascript中数组和字符串的方法对比

    下面小编就为大家带来一篇javascript中数组和字符串的方法对比。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • 在JavaScript中如何解决用execCommand(

    在JavaScript中如何解决用execCommand(

    这篇文章主要给大家介绍在JavaScript中如何解决用execCommand("SaveAS")保存页面兼容性问题,设计到execCommand兼容性问题,感兴趣的朋友可以参考下本篇文章
    2015-10-10
  • JavaScript的异步ajax详解

    JavaScript的异步ajax详解

    篇文章主要为大家详细介绍了JavaScript 异步ajax,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下吗,希望能够给你带来帮助
    2022-03-03
  • 用js实现CSS圆角生成更新

    用js实现CSS圆角生成更新

    用js实现CSS圆角生成更新...
    2007-05-05
  • JavaScript对数组进行随机重排的方法

    JavaScript对数组进行随机重排的方法

    这篇文章主要介绍了JavaScript对数组进行随机重排的方法,实例分析了javascript实现数组随机重新排序的两种实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • 微信小程序实现手势解锁的示例详解

    微信小程序实现手势解锁的示例详解

    手势解锁是生活中常用的解锁方式,本文将通过微信小程序实现手势解锁这一功能,本实例以工具的形式可以嵌入到不同的项目之中,感兴趣的可以了解一下
    2022-04-04
  • JavaScript 变量作用域及闭包

    JavaScript 变量作用域及闭包

    作用域JavaScript 的变量作用域是按照函数划分的,为了快速的了解它的特性,我们通过实例来进行演示。
    2009-08-08
  • 滚动条代码生成器

    滚动条代码生成器

    滚动条代码生成器...
    2007-02-02

最新评论