【进阶】Event Loop 常考面试题

在上一篇文章(面试官:聊一下 Event - Loop)中,我们探讨了 事件循环(Event Loop)的引入、概念及执行过程。今天的内容是之前的进阶,如果对今天的内容不太熟悉的掘友可以先看一下往期的作品。

今天我们将更进一步,深度剖析一道事件循环常考的面试题。

话不多说,先上题。

大试牛刀

请写出以下代码的打印顺序:

js 复制代码
console.log('script start')
async function async1() {
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2 end')
}
async1()
setTimeout(function () {
    console.log('setTimeout')
}, 0)
new Promise(resolve => {
    console.log('Promise')
    resolve()
})
    .then(function () {
        console.log('promise1')
    })
    .then(function () {
        console.log('promise2')
    })
console.log('script end')

【答案】(点击展开) script start

async2 end

Promise

script end

async1 end

promise1

promise2

setTimeout

我们先来回忆一下上一篇文章的知识:

事件循环的步骤

1.进入到script标签,script隶属于宏任务,进入第一次事件循环

2.遇到同步代码,立即执行

3.遇到宏任务,放入到宏任务队列里;遇到微任务,放入到微任务队列里

4.执行完所有同步代码,执行微任务代码

5.微任务代码执行完毕,寻找下一个宏任务

6.重复步骤1

这道题中出现了ansyc/await ,如果不清楚的同学可以展开看我的介绍,大佬则可选择跳过。

什么是 ansyc/await

对 ansyc/await 的介绍(点击展开)

什么是 ansyc/await

async/await 是 JS 中用于处理异步操作的一种语法糖,它基于 Promise,使得异步代码的编写和阅读更加简洁和清晰。async 函数用于定义一个返回 Promise 对象的异步函数,而 await 用于等待一个 Promise 对象的解决。简单点说,就是在Promise的基础上做了点优化,具体有哪些我们继续往后看。

现在有以下异步任务:

js 复制代码
function A() {
    setTimeout(()=>{
        console.log('异步A完成');
    },1000)
}
function B() {
    setTimeout(()=>{
        console.log('异步B完成');
    },500)
}
function C() {
    setTimeout(()=>{
        console.log('异步C完成');
    },100)
}
A()
B()
C()

正常调用这个三个函数,得到的打印结果为:

异步C完成

异步B完成

异步A完成

如果我们现在就是先要打印顺序为 ABC,那么我们一般会使用Promise(详情见------面向小白编程:Promise 的浅入深出

js 复制代码
function A() {
    return new Promise((resolve, reject)=> {
        setTimeout(()=>{
            console.log('异步A完成');
            resolve()
        },1000)
    })
}

function B() {
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            console.log('异步B完成');
            resolve()
        },500)
    })
}
function C() {
    setTimeout(()=>{
        console.log('异步C完成');
    },100)
}
A()
.then(()=>{
    return B()
})
.then(()=>{
    C()
})

通过Promise.then()方法我们能轻易控制异步任务的打印顺序。

但是今天我们又要介绍一种新的处理异步的方法------ansyc/await,如何使用呢?

1. 定义异步函数: 使用 async 关键字声明一个异步函数。异步函数会返回一个 Promise 对象。

js 复制代码
async function foo() {
  // 异步操作...
}

2. 使用 await 等待异步操作完成:foo 函数中,通过 await 关键字等待异步函数 ABC 完成。await 会暂停 foo 函数的执行,直到对应的异步操作完成。

js 复制代码
function A() {
    return new Promise((resolve, reject)=> {
        setTimeout(()=>{
            console.log('异步A完成');
            resolve()
        },1000)
    })
}
function B() {
    return new Promise((resolve, reject)=> {
        setTimeout(()=>{
            console.log('异步B完成');
            resolve()
        },500)
    })
}
function C() {
    return new Promise((resolve, reject)=> {
        setTimeout(()=>{
            console.log('异步C完成');
            resolve()
        },100)
    })
}

async function foo() {
    await A();  
    await B();  // 等待异步A完成
    await C();  // 等待异步B完成
}
foo();

3. 最终调用 foo函数就可以得到打印结果:

异步A完成

异步B完成

异步C完成


易错点

  1. promise本身是一个同步的代码,只有它后面调用的then()方法里面的回调才是微任务
  2. await右边的表达式会立即执行,表达式之后的代码,即表达式下方的代码会被阻塞,被推入微任务队列。

步骤分析

拿到这段代码,开始执行script宏任务,即进入第一次事件循环。遇到同步代码,立即执行;遇到宏任务,放入到宏任务队列里;遇到微任务,放入到微任务队列里。

当执行到 async1()时,await async2()立马执行打印async2 end ,而await后面的任务进入微任务队列。最终执行栈、宏任务队列和微任务队列所示如下:

同步代码执行完毕,开始执行微任务:

微任务队列为空,开始执行下一个宏任务,开始下一次事件循环:

这次循环中只有一个同步任务console.log('setTimeout'),直接打印。

综上所述,打印顺序为:

script start

async2 end

Promise

script end

async1 end

promise1

promise2

setTimeout

至此,这道面试题已经解决,如果你有任何疑惑欢迎评论区留言!

最后

看到这里,我相信你已经可以轻易回答事件循环相关的面试题了,愿你在面试的道路上取得优异的成绩,同时也在技术的海洋中扬帆起航,创造出更加精彩的前端世界。加油!

已将学习代码上传至 Github,欢迎大家学习指正!

技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!

相关推荐
某公司摸鱼前端7 分钟前
ES13(ES2022)新特性整理
javascript·ecmascript·es13
心平愈三千疾29 分钟前
通俗理解JVM细节-面试篇
java·jvm·数据库·面试
ai小鬼头1 小时前
百度秒搭发布:无代码编程如何让普通人轻松打造AI应用?
前端·后端·github
漂流瓶jz1 小时前
清除浮动/避开margin折叠:前端CSS中BFC的特点与限制
前端·css·面试
前端 贾公子1 小时前
在移动端使用 Tailwind CSS (uniapp)
前端·uni-app
散步去海边1 小时前
Cursor 进阶使用教程
前端·ai编程·cursor
清幽竹客1 小时前
vue-30(理解 Nuxt.js 目录结构)
前端·javascript·vue.js
weiweiweb8881 小时前
cesium加载Draco几何压缩数据
前端·javascript·vue.js
幼儿园技术家1 小时前
微信小店与微信小程序简单集成指南
前端
我不吃饼干9 天前
鸽了六年的某大厂面试题:你会手写一个模板引擎吗?
前端·javascript·面试