我的编程空间,编程开发者的网络收藏夹
学习永远不晚

深入理解JavaScript的事件执行机制

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

深入理解JavaScript的事件执行机制

前言

熟悉事件循环,了解浏览器运行机制将对我们理解 JavaScript 的执行过程和排查运行问题有很大帮助。以下是总结的一些浏览器事件循环的一些原理和示例。

浏览器 JS 异步执行的原理

  • JS 是单线程的,也就是同一个时刻只能做一件事情,那么,为什么浏览器可以同时执行异步任务呢?
  • 因为浏览器是多线程的,当 JS 需要执行异步任务时,浏览器会另外启动一个线程去执行该任务。
  • 也就是说,JS 是单线程的指的是 执行JS 代码的线程只有一个,是浏览器提供的 JS 引擎线程(主线程)。浏览器中还有定时器线程和 HTTP 请求线程等,这些线程主要不是来跑 JS 代码的。
  • 比如主线程中需要发一个 AJAX 请求,就把这个任务交给另一个浏览器线程(HTTP 请求线程)去真正发送请求,待请求回来了,再将 callback 里需要执行的 JS 回调交给 JS 引擎线程去执行。
  • 即浏览器才是真正执行发送请求这个任务的角色,而 JS 只是负责执行最后的回调处理。所以这里的异步不是 JS 自身实现的,其实是浏览器为其提供的能力。

浏览器中的事件循环

执行栈与任务队列

JS 在解析一段代码时,会将同步代码按顺序排在某个地方,即执行栈,然后依次执行里面的函数。
遇到异步任务时就交给其他线程处理,待当前执行栈所有同步代码执行完成后,会从一个队列中去取出已完成的异步任务的回调加入执行栈继续执行。
遇到异步任务时又交给其他线程,.....,如此循环往复。
而其他异步任务完成后,将回调放入任务队列中待执行栈来取出执行。

宏任务和微任务

根据任务的种类不同,可以分为微任务(micro task)队列和宏任务(macro task)队列。
事件循环的过程中,执行栈在同步代码执行完成后,优先检查微任务队列是否有任务需要执行,如果没有,再去宏任务队列检查是否有任务执行,如此往复。
微任务一般在当前循环就会优先执行,而宏任务会等到下一次循环,因此,微任务一般比宏任务先执行,并且微任务队列只有一个,宏任务队列可能有多个。另外我们常见的点击和键盘等事件也属于宏任务。

常见宏任务:

  • setTimeout()
  • setInterval()
  • UI交互事件
  • postMessage
  • setImmediate() -- nodeJs

常见微任务:

  • promise.then()、promise.catch()
  • new MutaionObserver()
  • process.nextTick() -- nodeJs

如下示例:


console.log('同步代码1');
setTimeout(() => {
    console.log('setTimeout')
}, 0)

new Promise((resolve) => {
  console.log('同步代码2')
  resolve()
}).then(() => {
    console.log('promise.then')
})
console.log('同步代码3');

// 最终输出"同步代码1"、"同步代码2"、"同步代码3"、"promise.then"、"setTimeout"

具体分析如下:

  • setTimeout 回调和 promise.then 都是异步执行的,将在所有同步代码之后执行;
  • 虽然 promise.then 写在后面,但是执行顺序却比 setTimeout 优先,因为它是微任务;
  • new Promise 是同步执行的,promise.then 里面的回调才是异步的。

注意: 在浏览器中 setTimeout 的延时设置为 0 的话,会默认为 4ms,NodeJS 为 1ms。
微任务和宏任务的本质区别:

  • 宏任务特征:有明确的异步任务需要执行和回调;需要其他异步线程支持。
  • 微任务特征:没有明确的异步任务需要执行,只有回调;不需要其他异步线程支持。

Async/await的运行顺序

特点

  • async声明的函数只是把该函数的return包装了,使得无论如何都会返回promise对象(非promise会转化为promise{resolve})。
  • await声明只能用在async函数中。
    • 当执行async函数时,遇到await声明,会先将await后面的内容按照'平常的执行规则'执行完(此处注意,当执行函数内容中又遇到await声明,此时接着执行该await声明内容)。
    • 执行完后立马跳出async函数,去执行主线程其他内容,等到主线程执行完再回到await处继续执行后面的内容。

示例


const a = async () => {
  console.log("a");
  await b();
  await e();
};

const b = async () => {
  console.log("b start");
  await c();
  console.log("b end");
};

const c = async () => {
  console.log("c start");
  await d();
  console.log("c end");
};

const d = async () => {
  console.log("d");
};

const e = async () => {
  console.log("e");
};

console.log('start');
a();
console.log('end');

运行结果

个人分析

  • 在当前同步环境中,先执行console.log('start');输出'start'。
  • 遇到同步函数a(),执行a()。
  • a()是sync/await构造,函数内遇到console.log("a") 输出 'a',遇到await声明 await b(),为异步函数,进入函数b()内执行。(类似的操作,我自己想的)并将 await b()后的内容推入微任务队列中。我们可以记做[await b()后]。
  • b()是sync/await构造,顺序执行遇到console.log("c start") 输出 'c start',遇到await声明 await c(),为异步函数,进入函数c()内执行。并将 await c()后的内容推入微任务队列中。我们可以记做[await c()后, await b()后]。
  • c()是sync/await构造,顺序执行遇到console.log("b start") 输出 'b start',遇到await声明 await d(),为异步函数,进入函数d()内执行。并将 await d()后的内容推入微任务队列中。我们可以记做[await d()后, await c()后, await b()后]。
  • d()中,顺序执行遇到console.log("") 输出 'd',d()函数运行结束。
  • 这是执行完 d()后,无可执行异步函数,此时进入同步环境,执行 a()后的内容。
  • 遇到console.log("end") 输出 'end'。此时同步环境中主线程执行完,检查微任务队列是否有微任务。
  • 微任务队列中[await d()后, await c()后, await b()后]有微任务,执行await d()后的内容。
  • wait d()后的内容是,console.log("c end"), 输出 'c end'。此时内容执行完毕,再从微任务队列中[await c()后, await b()后]检查,执行await c()后的内容。
  • 执行await c()后的内容,console.log("b end");, 输出 'b end'。此时内容执行完毕,再从微任务队列中[await b()后]检查,执行await b()后的内容。
  • await d()后的内容是,await e(),遇到await声明,执行e()。并判断并将 await e()后无运行代码,不用入微任务队列。
  • 执行e(),顺序执行console.log("e");,输出 'e'。此时函数结束。
  • 微任务队列中[]无微任务,执行结束。进入同步环境。

到此这篇关于深入理解JavaScript的事件执行机制的文章就介绍到这了,更多相关JavaScript 事件执行机制内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网! 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

深入理解JavaScript的事件执行机制

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

深入理解JavaScript事件机制

事件机制是几乎所有开发语言都有的机制,并不是deviceone的独创,在某些语言称之为消息(Event),有些地方称之为(Message).接下来通过本文给大家介绍JS事件机制的理解,需要的朋友一起学习吧
2023-05-17

web前端:关于javascript的事件执行机制理解

编程学习网:Javascript最初受java启发而开始设计的,目的之一就是“看上去像Java”,因此语法上有类似之处,一些名称和命名规范也借自Java。
web前端:关于javascript的事件执行机制理解
2024-04-23

深入理解异步事件机制

通过了解异步设计的由来,来深入理解异步事件机制。代码地址什么是异步同步并发(Concurrency)线程(Thread)I/O多路复用异步(Asynchronous)回调(Callback)参考文献为了深入理解异步的概念,就必须先了解异步设
2023-01-31

深入理解JavaScript执行上下文

只有理解了执行上下文,才能更好地理解 JavaScript 语言本身,比如变量提升,作用域,闭包等

JS的事件循环执行机制详解

JS执行是单线程的,它是基于事件循环的,那么本篇博文就来分享一下关于JS的事件循环执行机制,感兴趣的小伙伴可以跟着小编一起来学习
2023-05-19

这次,彻底理解 JavaScript 的执行机制

JavaScript 是一种单线程语言。尽管在最新的 HTML5 中引入了 Web Worker,但 JavaScript 的单线程核心没有改变。因此,JavaScript 中的所有“多线程”都是使用单线程模拟的,所有的多线程都是欺骗性的!

深入阐述JavaScript的运行机制

JavaScript是一种流行的编程语言,它几乎被用于网站和应用程序的开发中。对于初学者和许多开发人员来说,JavaScript似乎是单线程的,这意味着它只能同时执行一个任务。然而,JavaScript到底是不是真的单线程呢?这是一个有争议的话题,这篇文章将探讨这个话题并阐述JavaScript的运行机制。JavaScript是一种脚本语言,用于在网页上实现动态效果。它最初被设
2023-05-14

深入了解Node事件循环(EventLoop)机制

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。下面本篇文章就来带大家掌握Node.js中的eventloop,希望对大家有所帮助!
2023-05-14

深入理解 Android事件分发机制源码(基于9.0)

touch事件最开始从Activity 的 dispatchTouchEvent() 方法开始的/frameworks/base/core/java/android/app/Activity.java /*** Called to proc
2022-06-06

深入理解PHP逻辑运行机制

当我们谈论PHP的逻辑运行机制时,我们实际上是在探讨PHP是如何解释和执行我们写的代码的。PHP是一种服务器端脚本语言,它可以与HTML一起工作,从而创建动态网页。在本文中,我们将深入探讨PHP的逻辑运行机制,并通过具体的代码示例来帮助读者
深入理解PHP逻辑运行机制
2024-03-06

AndroidView的事件分发机制深入分析讲解

事件分发从手指触摸屏幕开始,即产生了触摸信息,被底层系统捕获后会传递给Android的输入系统服务IMS,通过Binder把消息发送到activity,activity会通过phoneWindow、DecorView最终发送给ViewGroup。这里就直接分析ViewGroup的事件分发
2023-01-29

带你深入了解Android的事件分发机制

Android的事件分发机制是指在Android系统中,如何将用户的触摸事件、按键事件等传递给正确的View进行处理的一套机制。它是Android应用程序中实现交互的重要部分,确保用户的操作能够被正确地捕获和处理。 Android的事件分发
2023-08-18

事件冒泡是什么?深入解析事件冒泡机制

事件冒泡是什么?深入解析事件冒泡机制事件冒泡是Web开发中一个重要的概念,它定义了页面上事件传递的方式。当一个元素上的事件被触发时,事件将会从最内层的元素开始传递,逐级向外传递,直到传递到最外层的元素。这种传递方式就像水泡在水中冒泡一样,
事件冒泡是什么?深入解析事件冒泡机制
2024-02-22

编程热搜

目录