【Vue3】Event Loop

JavaScript 的执行机制

单线程意味着所有任务需要排队执行,前面的完成,后面的任务才能执行。因此,如果前面的任务耗时太久,后面的任务就需要一直等,影响用户体验,所以出现了异步的概念。

JavaScript的执行机制是指JavaScript代码在浏览器或Node.js环境中运行时的工作原理。JavaScript是一种单线程、非阻塞、事件驱动的语言,虽然HTML5中JavaScript也支持了多线程webWorker,但是也是不允许操作DOM。其执行机制包括以下几个关键方面:

  1. 解析:

    • JavaScript代码首先会被解析器解析成抽象语法树(AST)。
    • 解析器会检查代码是否有语法错误,并将代码转换成可执行的指令。
  2. 执行上下文(Execution Context):

    • 在执行之前,JavaScript引擎会创建一个全局执行上下文(Global Execution Context)。
    • 每次调用函数时,都会创建一个新的函数执行上下文(Function Execution Context)。
    • 执行上下文包含变量环境、词法环境和this关键字的值。
  3. 作用域链(Scope Chain):

    • JavaScript中的作用域是通过作用域链来管理的。
    • 每个执行上下文都有自己的词法环境,其中包含了变量和函数声明。
    • 当查找变量或函数时,JavaScript引擎会从当前执行上下文的词法环境开始,逐级向外层作用域查找,直到找到匹配的标识符或达到全局作用域。
  4. 变量提升(Hoisting):

    • JavaScript中的变量和函数声明会被提升到其所在作用域的顶部。
    • 这意味着你可以在声明之前使用变量和函数,但它们的实际赋值或执行是在代码中的位置决定的。
  5. 执行栈(Call Stack):

    • 执行上下文以栈的形式管理,这被称为调用栈(Call Stack)。
    • 当函数被调用时,其执行上下文被推入调用栈的顶部;当函数执行完成时,该执行上下文被弹出栈。
    • 这保证了JavaScript是单线程的,一次只能执行一个任务(函数调用)。
  6. 事件循环(Event Loop):

    • JavaScript运行时环境(浏览器或Node.js)提供了一个事件循环来处理异步操作。
    • 异步任务(例如定时器、事件处理程序、HTTP请求等)被放入任务队列(Task Queue)中。
    • 当调用栈为空时,事件循环会将任务队列中的任务一个一个地移入调用栈执行。
  7. 回调函数:

    • 异步操作通常使用回调函数来处理。
    • 当异步操作完成时,回调函数被添加到任务队列,并在适当的时候执行。
  8. Promise和async/await:

    • Promise和async/await是用来处理异步操作的现代JavaScript特性,它们提供了更清晰、可读性更好的异步编程方式。

同步任务

代码从上到下按顺序依次执行。

异步任务

1. 宏任务

DOM操作导致的事件(例如,元素的变动、事件监听器)、setTimeout、setInterval、用户交互事件(例如点击事件)、postMessage、Ajax、XMLHttpRequest或fetch等网络请求

2. 微任务

Promise.then / catch / finally、MutationObserver变动观察器的回调函数、process.nextTick(Node.js 环境)、async/await中的await关键字

执行顺序:

  1. 同步任务在主进程执行形成一个执行栈,主线程之外,还存在一个"任务队列",里面存放异步任务。
  2. 先执行一个宏任务,也就是先加载整个script,这就算是一个宏任务。
  3. 执行所有的微任务(Microtasks)。
  4. 从宏任务队列中再取出一个宏任务(Macrotask)执行。
  5. 执行可能产生的 UI 重渲染。
  6. 重复以上步骤,直到所有的任务队列为空。

看一道题:

ts 复制代码
async function Prom() {
  console.log('Y')

  await Promise.resolve()
  console.log('x')
}
setTimeout(() => {
  console.log(1)
  Promise.resolve().then(() => {
    console.log(2)
  })
}, 0)
setTimeout(() => {
  console.log(3)
  Promise.resolve().then(() => {
    console.log(4)
  })
}, 0)
Promise.resolve().then(() => {
  console.log(5)
})
Promise.resolve().then(() => {
  console.log(6)
})
Promise.resolve().then(() => {
  console.log(7)
})
Promise.resolve().then(() => {
  console.log(8)
})
Prom()
console.log(0)
// 输出结果是: Y 0 5 6 7 8 x 1 2 3 4

分析:

  1. setTimeout 是异步宏任务,放入宏任务队列
  2. Promise.then() 是异步微任务,放入微任务队列
  3. Prom 同步代码,立刻执行,输出 Y 。但遇到 await 微任务,再次放入微任务队列,等候。
  4. 执行console.log同步代码,输出0
  5. 到目前为止,相当于 script 宏任务执行结束,开始执行所有的微任务。
  6. 查看微任务队列,依次执行微任务 Promise.then() ,输出 5,6,7,8
  7. 对了,不要忘记下一个微任务还有过程3中遇到的 await 微任务,后面的 Promise.resolve()consonle.log('x') 相当于是 Promise.resolve().then(()=>console.log('x')) ,所以然后输出x
  8. 到此,微任务队列执行完,继续执行下一个宏任务队列 setTimeout ,输出 1 ,然后又遇到 Promise ,放入到微任务队列。
  9. 每次执行完宏任务都需要清空微任务队列,所以执行 Promise 输出 2 。
    10.下一个setTimeout 中包含 Promise 也是同理,因此依次输出 2 4
相关推荐
让开,我要吃人了2 小时前
HarmonyOS开发实战(5.0)实现二楼上划进入首页效果详解
前端·华为·程序员·移动开发·harmonyos·鸿蒙·鸿蒙系统
Passion不晚2 小时前
Vue vs React vs Angular 的对比和选择
vue.js·react.js·前端框架·angular.js
everyStudy3 小时前
前端五种排序
前端·算法·排序算法
甜兒.4 小时前
鸿蒙小技巧
前端·华为·typescript·harmonyos
她似晚风般温柔7896 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr8 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy8 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白8 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、8 小时前
Web Worker 简单使用
前端
web_learning_3218 小时前
信息收集常用指令
前端·搜索引擎