js event loop事件队列详解(浏览器中)

简介: js event loop事件队列详解(浏览器中)

目录


前言

js是单线程的

认识一个栈两个队列

执行过程

异步任务怎么分配

简单例子

难一点的例子


前言



以下内容是js在浏览器中的事件队列执行,与在nodejs中有所区别,请注意。


js是单线程的



要知道js是单线程的,就是一件一件做,做完一件做下一件。


认识一个栈两个队列



一个调用栈Stack。

一个宏队列,macrotask,也叫tasks。

一个微队列,microtask,也叫jobs。


执行过程



js就是执行全局Script同步代码,这中间碰到一些异步任务先加进对应的队列。


做完之后,调用栈就为空了。


然后将队列(先微队列后宏队列)里面的首个任务提到调用栈来做,一件一件做完直到队列中的任务都做完。


总结就是,先做同步的任务,再做微队列的任务,再做宏队列的任务。


异步任务怎么分配



这些异步任务包括但不限于:


以下分配给宏队列:


setTimeout

setInterval

requestAnimationFrame

I/O

UI rendering

以下分配给微队列:


Promise

Object.observe

MutationObserver

常见的宏队列:setTimeout,常见的微队列:Promise。


简单例子


    console.log("同步任务1");
    setTimeout(() => {
      console.log("宏任务");
    });
    new Promise((resolve, reject) => {
      console.log("同步任务2");
      resolve("微任务");
    }).then((data) => {
      console.log(data);
    });
    console.log("同步任务3");

结果是(按标号加任务,按箭头执行):

image.png

image.png

需要注意的是Promise的第一层没有执行回调之前是同步的,也就是上面的同步任务2。

难一点的例子


    console.log("同步任务1");
    console.log("同步任务2");
    new Promise((resolve, reject) => {
      console.log("同步任务3");
      setTimeout(() => {
        console.log("宏任务1");
        Promise.resolve()
          .then(() => {
            console.log("微任务5");
          })
          .then(() => {
            console.log("微任务6");
          });
      });
      resolve("微任务1");
    })
      .then((data) => {
        console.log(data);
        return "微任务3";
      })
      .then((data) => {
        console.log(data);
      });
    setTimeout(() => {
      console.log("宏任务2");
    }, 0);
    new Promise((resolve, reject) => {
      resolve("微任务2");
    })
      .then((data, resolve) => {
        console.log(data);
        return "微任务4";
      })
      .then((data) => {
        console.log(data);
      });
    console.log("同步任务4");

如何看呢,先看第一层,红色代表同步,绿色微任务,蓝色宏任务。

我们会把同步任务执行完,然后看见微任务有俩,宏任务也有俩。

本来的执行顺序可能是这样(我这里按照序号来表达顺序了,请和简单例子区分开来):

image.png

但是没那么顺利,执行到标号6时不一样了。


因为微任务执行过程中可能会产生新的微任务。


上面的微任务1执行完会把微任务3加在微任务2后面,也就是微任务2执行完也轮不到宏任务,会继续执行新的微任务直到微任务队列暂时为空。


所以接下来会按照加入队列的顺序执行完四个微任务,这时候发现没有新的微任务产生,才开始执行宏任务

image.png

但是需要注意的是,上面执行到标号5时又不一样了,宏任务一执行后又产生了新的微任务,所以宏任务两个并没有顺利连续执行,而是被插入的微任务拦住了。

(要记住微任务与宏任务队列都存在时一定是微任务先执行完再来执行宏任务,即使是宏任务执行产生的微任务也同理)

image.png

所以最后的答案,如果存在不理解的,可以在认真回顾一下上文:

image.png

相关文章
|
编解码 JavaScript 前端开发
【Java进阶】详解JavaScript的BOM(浏览器对象模型)
总的来说,BOM提供了一种方式来与浏览器进行交互。通过BOM,你可以操作窗口、获取URL、操作历史、访问HTML文档、获取浏览器信息和屏幕信息等。虽然BOM并没有正式的标准,但大多数现代浏览器都实现了相似的功能,因此,你可以放心地在你的JavaScript代码中使用BOM。
357 23
|
算法 开发者
Moment.js库是如何处理不同浏览器的时间戳格式差异的?
总的来说,Moment.js 通过一系列的技术手段和策略,有效地处理了不同浏览器的时间戳格式差异,为开发者提供了一个稳定、可靠且易于使用的时间处理工具。
813 156
|
JavaScript 前端开发 Java
【Java进阶】详解JavaScript事件
总的来说,JavaScript事件是JavaScript交互设计的核心,理解和掌握JavaScript事件对于编写高效、响应式的网页应用至关重要。
241 15
|
Web App开发 前端开发 JavaScript
折腾之王:JavaScript之父Brave浏览器与BAT的诞生
2015年,JavaScript之父Brendan Eich再次创业,推出Brave浏览器和加密货币Basic Attention Token(BAT),旨在颠覆传统广告行业。Brave屏蔽广告、保护隐私,加载速度快;BAT则通过奖励机制让用户、内容创作者和广告主三方受益。尽管面临用户习惯和巨头竞争的挑战,Brave已拥有超4000万月活跃用户,成为全球增长最快的隐私浏览器,引领Web3生态发展。
524 22
折腾之王:JavaScript之父Brave浏览器与BAT的诞生
|
JavaScript 前端开发 数据处理
模板字符串和普通字符串在浏览器和 Node.js 中的性能表现是否一致?
综上所述,模板字符串和普通字符串在浏览器和 Node.js 中的性能表现既有相似之处,也有不同之处。在实际应用中,需要根据具体的场景和性能需求来选择使用哪种字符串处理方式,以达到最佳的性能和开发效率。
406 63
|
移动开发 JavaScript 前端开发
一些处理浏览器兼容性问题的JavaScript库
这些库在处理浏览器兼容性问题方面都有着各自的特点和优势,可以根据具体的需求和项目情况选择合适的库来使用,从而提高代码的兼容性和稳定性,为用户提供更好的体验。同时,随着浏览器技术的不断发展,还需要持续关注和学习新的兼容性解决方案。
460 58
|
JavaScript 前端开发 测试技术
盘点原生JavaScript中直接触发事件的方式
本文全面探讨了原生JavaScript中触发事件的多种方式,包括`dispatchEvent`、`Event`构造函数、`CustomEvent`构造器、直接调用事件处理器以及过时的`createEvent`和`initEvent`方法。通过技术案例分析,如模拟点击事件、派发自定义数据加载事件和实现提示框系统,帮助开发者掌握这些方法在实际开发中的应用,提升灵活性与兼容性。
555 3
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
887 5
|
JSON 移动开发 JavaScript
在浏览器执行js脚本的两种方式
【10月更文挑战第20天】本文介绍了在浏览器中执行HTTP请求的两种方式:`fetch`和`XMLHttpRequest`。`fetch`支持GET和POST请求,返回Promise对象,可以方便地处理异步操作。`XMLHttpRequest`则通过回调函数处理请求结果,适用于需要兼容旧浏览器的场景。文中还提供了具体的代码示例。
303 5
在浏览器执行js脚本的两种方式
下一篇
开通oss服务