一文带你彻底弄懂js事件循环(Event Loop)

JavaScript事件循环是JavaScript运行时环境中处理异步操作的机制。它允许JavaScript在执行同步代码的同时处理异步任务,以避免阻塞线程并提供更好的用户体验。

本文将在浏览器异步执行原理基础上带你彻底弄懂js的事件循环机制。

浏览器JS异步执行原理

js是单线程的,也就是说同一时刻只能做一件事情。
作为一个浏览器脚本语言,这与javascript的用途有关。

JavaScript主要用于与用户进行交互和操作文档对象模型(DOM)。在网页中,用户的操作和页面的渲染是非常重要的,如果JavaScript是多线程的,可能会导致多个线程同时修改DOM,造成不可预测的结果。

因此,为了保证页面的安全性和稳定性,JavaScript被设计为单线程的。它使用事件循环机制来处理异步任务,确保任务的按序执行,避免了多线程带来的竞态条件和死锁等问题。

虽然JavaScript是单线程的,但是通过异步编程模型,可以实现非阻塞的操作。例如,通过使用回调函数、Promise、async/await等方式,可以在执行异步任务时,不会阻塞后续的代码执行,从而提高了程序的响应性能。

需要注意的是,虽然JavaScript本身是单线程的,但是浏览器是多线程的。浏览器中除了JavaScript引擎线程外,还有渲染线程、网络线程、定时器线程等。这些线程可以并行执行,提高了浏览器的性能和用户体验。但是JavaScript代码本身在执行时仍然是单线程的。
在这里插入图片描述

执行栈与任务队列

1. 执行栈(Call Stack):
执行栈是一种数据结构,用于管理函数的执行上下文(execution context)。当函数被调用时,会创建一个对应的执行上下文,并将其推入执行栈的顶部。执行栈遵循先进后出(LIFO)的原则,即最后进入的执行上下文最先执行,执行完毕后会从栈顶弹出。

当JavaScript引擎执行代码时,会将函数调用和表达式求值的过程以栈的形式进行管理。每当遇到函数调用时,会将该函数的执行上下文推入执行栈,然后执行函数体中的代码。如果函数内部又调用了其他函数,会将新的执行上下文推入执行栈,形成嵌套的执行上下文。

当函数执行完毕或遇到return语句时,会将该执行上下文从执行栈中弹出,继续执行之前的上下文。当执行栈为空时,表示所有的函数都已执行完毕,程序结束。

2. 任务队列(Task Queue):
任务队列是一种用于存储待执行的任务的队列。在JavaScript中,任务队列主要用于存储异步任务的回调函数。

当遇到异步任务(如定时器、网络请求、事件监听等)时,会将相应的回调函数放入任务队列中,而不会立即执行。当执行栈为空时,JavaScript引擎会从任务队列中取出一个任务,将其对应的回调函数推入执行栈,开始执行。

任务队列采用先进先出(FIFO)的原则,即先进入队列的任务会先被执行。这保证了异步任务按照其被触发的顺序执行,避免了回调函数的竞争和混乱。

通过执行栈和任务队列的协作,JavaScript实现了异步编程模型,使得程序能够在等待异步任务完成的同时继续执行其他任务,提高了程序的并发性和响应性能。

我们看下面一个列子更深入的理解一下执行栈和任务队列这个概念:

   console.log('1')
   setTimeout(() => {
     console.log('2')
   },0)
   console.log('3')
   //1 3 2

在这里插入图片描述
由上图可以清晰的看出,同步代码直接放入执行栈立即执行,而异步代码则被放入了宿主环境中,而宿主环境中的代码会等待正确的时机,时机一到宿主环境会把里面的回调函数推送给任务队列执行栈执行完之后会看任务队列里面有没有异步任务,有则把里面的代码推送到执行栈中执行。

宏任务和微任务

任务队列中的任务分为宏任务(macro-task)和微任务(micro-task)两种类型。宏任务包括定时器任务、事件任务等,而微任务主要包括Promise的回调函数、MutationObserver的回调函数等。微任务的执行优先级高于宏任务,即在执行栈为空时,会先执行所有的微任务,然后再执行宏任务。

1. 宏任务(macro-task)(宿主环境-浏览器、node):
宏任务是一类较为重量级的任务,包括但不限于以下几种:

  • 定时器任务(setTimeout、setInterval等)
  • I/O任务(文件读写、网络请求等)
  • UI渲染任务(页面重绘、动画渲染等)
  • 事件任务(鼠标点击、键盘事件等)

宏任务会被推入任务队列中,在执行栈为空时,JavaScript引擎会从任务队列中取出一个宏任务,将其对应的回调函数推入执行栈,开始执行。宏任务之间的执行顺序是按照它们被添加到任务队列的顺序来执行的。

2. 微任务(micro-task)(js引擎):
微任务是一类较为轻量级的任务,主要包括以下几种:

  • Promise的回调函数(then、catch、finally)
  • MutationObserver的回调函数
  • process.nextTick(Node.js环境)

微任务会在当前宏任务执行完毕后立即执行,而不需要等待其他宏任务。当执行栈为空时,JavaScript引擎会先执行所有的微任务,然后再执行下一个宏任务。微任务之间的执行顺序是按照它们被添加到任务队列的顺序来执行的。
接着上面的列子再来分析一下:

    console.log('1')
    setTimeout(() => {
      console.log('2')
    },0)
    new Promise(function (resolve) {
	    console.log('promise1')
	    resolve()
        console.log('promise2')
    }).then(function () {
        console.log('promise3')
    })
    console.log('3')
    //1 promise1 promise2 3 promise3 2

在这里插入图片描述
上图可清晰的看出,首先执行执行栈中的任务,依次打印1-promise1-promise2-3,然后把微任务中的任务放到执行栈中,打印promise3,微任务队列执行完之后,再把宏任务中的队列放到执行栈中执行,打印2

总结

javaScript事件循环是一种用于管理和调度异步代码执行的机制。它的核心思想是通过执行栈、任务队列和事件触发来实现异步编程。

事件循环的执行过程可以总结如下:

1. 执行全局同步代码:
首先,JavaScript引擎会执行全局上下文中的同步代码,将函数调用和表达式求值的过程以栈的形式进行管理,即执行栈(Call Stack)。

2. 处理微任务:
在执行全局同步代码的过程中,如果遇到微任务(Promise的回调函数、MutationObserver的回调函数等),会将其推入微任务队列。

3. 处理宏任务:
当执行栈为空时,JavaScript引擎会从任务队列中取出一个宏任务,将其对应的回调函数推入执行栈,开始执行。宏任务包括定时器任务(setTimeout、setInterval等)、I/O任务(文件读写、网络请求等)、UI渲染任务(页面重绘、动画渲染等)和事件任务(鼠标点击、键盘事件等)。

4. 处理微任务:
在执行完一个宏任务后,会检查微任务队列是否为空,如果不为空,则依次执行所有的微任务。微任务的执行优先级高于宏任务,即在同一个宏任务中,会先执行所有的微任务,然后再执行下一个宏任务。

5. 重复执行步骤3和步骤4:
事件循环会不断重复执行步骤3和步骤4,直到执行栈和任务队列都为空。

需要注意的是,事件循环是单线程的,即一次只能执行一个任务。当一个任务正在执行时,其他任务需要等待。这也是为什么长时间运行的任务会阻塞UI渲染和其他任务的原因。

合理地使用异步编程和事件循环机制可以提高程序的性能和响应性能,避免了阻塞和卡顿。同时,需要注意避免过多的嵌套回调和过度依赖异步操作,以免造成代码可读性和维护性的问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103是意法半导体(STMicroelectronics)推出的一款32位单片机系列,属于Cortex-M3内核。下面是一份简要的说明,帮助你了解STM32F103。 1. 内核架构:STM32F103采用ARM Cortex-M3内核,具有较高的性能和低功耗特性。它运行在最高72MHz频率下。 2. 存储器:STM32F103具有不同的存储器选项,包括闪存(Flash)和随机存取存储器(SRAM)。闪存用于存储程序代码和常量数据,SRAM用于存储变量和堆栈。 3. 外设:STM32F103拥有丰富的外设,包括通用定时器、串行通信接口(USART、SPI、I2C)、模数转换器(ADC)、通用输入输出引脚(GPIO)等。这些外设可用于实现各种应用,如控制、通信和传感器接口。 4. 开发环境:对于STM32F103的开发,你可以使用ST提供的官方开发工具——STM32CubeIDE,它是基于Eclipse的集成开发环境。此外,你还可以使用其他第三方软件,如Keil MDK或IAR Embedded Workbench。 5. 编程语言:你可以使用C/C++编程语言进行STM32F103的开发。ST提供了丰富的库函数和示例代码,方便开发者快速上手。 6. 资源:为了更好地了解STM32F103,你可以参考ST官方的技术文档、数据手册和应用笔记。此外,CSDN等网站上也有很多关于STM32F103的教程和案例供你学习参考。 需要注意的是,上述信息只是对STM32F103的一个简要介绍,如果你希望深入了解它的特性和开发方法,建议你查阅更多资料并进行实际的开发练习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值