【面试题】手写async await核心原理,再也不怕面试官问我async await原理

前言
async await 语法是 ES7出现的,是基于ES6的 promise和generator实现的
generator函数
在之前我专门讲个generator的使用与原理实现,大家没了解过的可以先看那个手写generator核心原理,再也不怕面试官问我generator原理
这里就不再赘述generator,专门的文章讲专门的内容。
await在等待什么
我们先看看下面这代码,这是async await的最简单使用,await后面返回的是一个Promise对象:
async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
}
getResult()
但不知你有没有想过一个问题,为什么会等到返回的promise的对象的状态为非pending的时候才会继续往下执行,也就是resolve执行之后,才会继续执行,就像下面的代码一样
async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
console.log(2);
}
getResult()

可以看到运行结果是先打印了1,再打印2了,也就是说明在返回的promise对象没执行resolve()前,就一直在await,等它执行。然后再执行下面的程序,那这个是怎么实现的呢?
原理实现
我们看一下下面的代码,输出顺序是什么?
async function getResult() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
getResult()
没错是 1,2,3.
那用generator函数专门来实现这个效果呢
我一开始这样来实现:
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
gen.next();
gen.next();
gen.next();
但是发现打印顺序是 3,2,1.明显不对。
这里的问题主要是三个 new Promise几乎是同一时刻执行了。才会出现这种问题,所以需要等第一个promise执行完resolve之再执行下一个,所以要这么实现
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
gen.next().value.then(() => {
gen.next().value.then(() => {
gen.next();
});
});

可以看到这样就打印正常了。
特别 需要解释下。gen.next().value 就是返回的promise对象,不理解的可以看看文首介绍的那篇generator的 文章。手写generator核心原理,再也不怕面试官问我generator原理
优化
但是呢,总不能有多少个await,就要自己写多少个嵌套吧,所以还是需要封装一个函数,显然,递归实现最简单
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
function co(g) {
g.next().value.then(()=>{
co(g)
})
}
co(gen)
再来看看打印结果

可以发现成功执行了,但是为什么报错了?
这是因为generator方法会返回四次,最后一次的value是undefined。
而实际上返回第三次就表示已经返回done,代表结束了,所以,我们需要判断是否是已经done了,不再让它继续递归
所以可以改成这样
function* getResult(params) {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
console.log(1);
}, 1000);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
console.log(2);
}, 500);
})
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
console.log(3);
}, 100);
})
}
const gen = getResult()
function co(g) {
const nextObj = g.next();
if (nextObj.done) {
return;
}
nextObj.value.then(()=>{
co(g)
})
}
co(gen)

可以看到这样就实现了。
总结给大家推荐一个实用面试题库
1、前端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
2、前端技术导航大全 推荐:★★★★★
地址:前端技术导航大全
3、开发者颜色值转换工具 推荐:★★★★★
地址 :开发者颜色值转换工具
【面试题】手写async await核心原理,再也不怕面试官问我async await原理的更多相关文章
- 看完这一篇,再也不怕面试官问到IntentService的原理
IntentService是什么 在内部封装了 Handler.消息队列的一个Service子类,适合在后台执行一系列串行依次执行的耗时异步任务,方便了我们的日常coding(普通的Service则是 ...
- [每日一题]面试官问:Async/Await 如何通过同步的方式实现异步?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
- 手写webpack核心原理,再也不怕面试官问我webpack原理
手写webpack核心原理 目录 手写webpack核心原理 一.核心打包原理 1.1 打包的主要流程如下 1.2 具体细节 二.基本准备工作 三.获取模块内容 四.分析模块 五.收集依赖 六.ES6 ...
- 深度剖析Java的volatile实现原理,再也不怕面试官问了
上篇文章我们讲了synchronized的用法和实现原理,我们总爱说synchronized是重量级锁,volatile是轻量级锁.为什么volatile是轻量级锁,体现在哪些方面?以及volatil ...
- 如何完美回答面试官问的Mybatis初始化原理!!!
前言 对于任何框架而言,在使用前都要进行一系列的初始化,MyBatis也不例外.本章将通过以下几点详细介绍MyBatis的初始化过程. MyBatis的初始化做了什么 MyBatis基于XML配置文件 ...
- [每日一题]面试官问:for in和for of 的区别和原理?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
- 「每日一题」有人上次在dy面试,面试官问我:vue数据绑定的实现原理。你说我该如何回答?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 来源:原创 一.前言 文章首发在「松宝写代码」 2020. ...
- JAVA面试题 手写ArrayList的实现,在笔试中过关斩将?
面试官Q1:可以手写一个ArrayList的简单实现吗? 我们都知道ArrayList是基于数组实现,如果让你实现JDK源码ArrayList中add().remove().get()方法,你知道如何 ...
- 常见python面试题-手写代码系列
1.如何反向迭代一个序列 #如果是一个list,最快的方法使用reversetempList = [1,2,3,4]tempList.reverse()for x in tempList: pr ...
- (手写)mybatis 核心配置文件和接口不在同一包下的解决方案
smart-sh-mybatis项目 app.xml文件中此处配置为: <!-- 从整合包里找,org.mybatis:mybatis-spring:1.2.4 --> <!-- s ...
随机推荐
- 20 张图带你全面了解 HTTPS 协议,再也不怕面试问到了!
本文详细介绍了 HTTPS 相较于 HTTP 更安全的原因,包括对称加密.非对称加密.完整性摘要.数字证书以及 SSL/TLS 握手等内容,图文并茂.理论与实战结合.建议收藏! 1. 不安全的 HTT ...
- python数据分析与可视化【思维导图】
python数据分析与可视化常用库 numpy+matplotlib+pandas 思维导图 图中难免有错误,后期随着学习与应用的深入,会不断修改更新. 当前版本号:1.0 numpy介绍 NumPy ...
- DVWA靶场实战(一)——Brute Force
DVWA靶场实战(一) 一.Brute Force: 1.漏洞原理: Brute Force是暴力破解的意思,大致原理就是利用穷举法,穷举出所有可能的密码. 2.攻击方法: Burpsuite中的In ...
- 在 K8S Volume 中使用 subPath
使用 subPath 有时,在单个 Pod 中共享卷以供多方使用是很有用的. volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径. 下面是一个使用同一共享卷的 ...
- Java学习笔记 :2021年12月31日 上午
Java学习笔记 :2021年12月31日 上午 目录 Java学习笔记 :2021年12月31日 上午 关于计算机语言 1.关于语言的分类 2.小结 关于Java语言的基础语法 1.主方法 2.其他 ...
- 02-Sed语法介绍
1 Sed语法介绍 介绍Sed支持的基本命令及其命令行语法,Sed可以通过以下两种形式进行调用: 学习sed命令使用之前,需要掌握正则表达式的用法. sed [-n] [-e] 'commands' ...
- 安装部署Java项目
开头:之前做了个文档转换的小项目,想部署在安卓手机上,自己可以随时看看,所以才有了下面这篇文章,内容或有瑕疵,望请批正.文末放我自己部署文档转换网址,仅供大家参考,谢谢! 选择:Termux 还是 L ...
- 今天试试NuxtJS
nuxt可以大幅缩短首屏加载时间 Progressive Web App (PWA) Support 渐进式web应用 简单说 就是让你的web应用表现的就像本地应用一样,可以添加快捷方式 打开的时候 ...
- 如何修剪git reflog历史
背景: vscode插件git-graph可以方便查看git-commit-graph,效果很好,关键是交互性很好.点选任意commit即可预览提交内容,实在是太方便了,比我之前用命令行上git lo ...
- appium之安卓7.0环境搭建
appium 在安卓7.0的手机上运行上报错---------Failure [INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install io.appi ...