面试官😏: 讲一下事件循环 ,顺便做道题🤪

题目

倔友们一起看一下把 ~

面试官 : 讲一下事件循环 , 顺便做了一道题🤪:下面字母的输出顺序是什么 ?

js 复制代码
async function async1() {
  console.log('E'); 
  await async2();
  console.log('F');
}

async function async2() {
  console.log('G');
}

setTimeout(() => console.log('H'), 0);
async1(); 
new Promise((res) => {
  console.log('I'); 
  res();
}).then(() => console.log('J'))

这是一段涉及 JavaScript 中异步操作( async/await 、 Promise 、 setTimeout )的代码,要确定其执行顺序,需要了解这些异步机制的执行原理------ 事件循环机制(Event loop)

答案 : E 、 G 、 I 、 F 、 J 、 H

不清楚的倔友一起往下看 :

事件循环

事件循环是JavaScript中用于

  • 处理异步操作
  • 协调事件处理

在网页开发中,事件循环确保用户界面的响应性。例如,当用户点击按钮时,点击事件作为一个宏任务被放入任务队列,在合适的时机被处理。在处理网络请求时,发起请求是异步操作,不会阻塞其他代码执行,请求完成后,响应数据的处理函数会作为一个宏任务或微任务被放入任务队列,等待执行。

基本概念

JavaScript是单线程语言,同一时间只能执行一个任务,但可以通过事件循环来实现异步操作。事件循环允许JavaScript在执行同步任务的同时,处理各种异步任务,如网络请求、定时器、用户交互等,不会因为某个耗时的操作而阻塞整个程序的运行。

工作原理

  • 执行栈:也叫调用栈,是一种存储函数调用关系的数据结构。当函数被调用时,会被压入执行栈,函数执行完毕后从栈顶弹出。JavaScript引擎会按照顺序执行执行栈中的函数。
  • 任务队列 :包括宏任务队列和微任务队列。
    • 宏任务包括 setTimeout 、 setInterval 、 setImmediate (Node.js环境)、I/O操作、UI渲染等
    • 微任务包括 Promise 的回调、 MutationObserver 等
  • 循环机制 :事件循环首先会检查执行栈 是否为空,如果为空,则检查微任务队列 是否有任务。如果有微任务,就会依次执行微任务队列中的所有任务,直到微任务队列为空。然后,事件循环会检查宏任务队列,从宏任务队列中取出一个宏任务放入执行栈执行,执行完这个宏任务后,再次检查微任务队列并执行其中的任务,如此循环往复。

执行流程图

这张图说明了一下几个点 :

  • 同步代码先执行
  • 异步代码先执行宏任务 , 再执行微任务

这个时候 , 我们再来看这段代码的执行顺序 ,简直是有手就行 ~

首先执行同步代码,遇到 setTimeout(() => console.log('H'), 0); , setTimeout 会将其回调函数放入宏任务队列中,暂不执行。

接着调用 async1() ,进入 async1 函数,首先执行 console.log('E'); ,输出 E 。

然后遇到 await async2(); ,先执行 async2 函数, async2 函数中 console.log('G'); ,输出 G 。此时 await 会暂停 async1 函数的执行,将 async1 函数中 await 后面的代码( console.log('F'); )放入微任务队列中。

继续执行同步代码,遇到 new Promise((res) => { console.log('I'); res(); }).then(() => console.log('J')); , Promise 的构造函数中的 console.log('I'); 会立即执行,输出 I ,并且 Promise 状态变为 fulfilled ,其 then 回调函数会被放入微任务队列中。

此时同步代码执行完毕 ,开始处理微任务队列。先执行 async1 函数中 await 后面被放入微任务队列的 console.log('F'); ,输出 F 。

接着执行 Promise 的 then 回调函数 console.log('J'); ,输出 J 。

微任务队列处理完毕后 ,开始处理宏任务队列,执行 setTimeout 的回调函数 console.log('H'); ,输出 H 。

综上所述,这段代码的执行顺序是: E 、 G 、 I 、 F 、 J 、 H 。

总结

两个点

  • 顺序 :同步代码 => 微任务 => 宏任务
  • 循环 :宏任务 => 微任务 , 没有微任务继续执行宏任务
相关推荐
好好研究27 分钟前
使用JavaScript实现轮播图的自动切换和左右箭头切换效果
开发语言·前端·javascript·css·html
程序视点4 小时前
IObit Uninstaller Pro专业卸载,免激活版本,卸载清理注册表,彻底告别软件残留
前端·windows·后端
前端程序媛-Tian5 小时前
【dropdown组件填坑指南】—怎么实现下拉框的位置计算
前端·javascript·vue
嘉琪0015 小时前
实现视频实时马赛克
linux·前端·javascript
烛阴5 小时前
Smoothstep
前端·webgl
若梦plus6 小时前
Eslint中微内核&插件化思想的应用
前端·eslint
爱分享的程序员6 小时前
前端面试专栏-前沿技术:30.跨端开发技术(React Native、Flutter)
前端·javascript·面试
超级土豆粉6 小时前
Taro 位置相关 API 介绍
前端·javascript·react.js·taro
若梦plus6 小时前
Webpack中微内核&插件化思想的应用
前端·webpack
若梦plus6 小时前
微内核&插件化设计思想
前端