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

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

相关推荐
黑客老陈31 分钟前
面试经验分享 | 北京渗透测试岗位
运维·服务器·经验分享·安全·web安全·面试·职场和发展
@解忧杂货铺2 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js
F-2H3 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
gqkmiss4 小时前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件
m0_748247556 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255026 小时前
前端常用算法集合
前端·算法
真的很上进7 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203987 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2347 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
测试老哥7 小时前
外包干了两年,技术退步明显。。。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展