【进阶】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,欢迎大家学习指正!

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

相关推荐
小白学大数据5 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_3901617714 分钟前
防抖函数--应用场景及示例
前端·javascript
3345543242 分钟前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test44 分钟前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫1 小时前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web