记录--通过手写,分析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)

可以看到这样就实现了。
完美,这个co其实也是大名鼎鼎的co函数的简单写法
本篇文章关于async 和 await的原理揭秘就到此为止了,再讲下去就不礼貌了。
本文转载于:
https://juejin.cn/post/7136424542238408718
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--通过手写,分析async await核心原理的更多相关文章
- 【面试题】手写async await核心原理,再也不怕面试官问我async await原理
前言 async await 语法是 ES7出现的,是基于ES6的 promise和generator实现的 generator函数 在之前我专门讲个generator的使用与原理实现,大家没了解过的 ...
- Promise及Async/Await
一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪 ...
- 异步Promise及Async/Await最完整入门攻略
一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪圈, ...
- 异步Promise及Async/Await可能最完整入门攻略
此文只介绍Async/Await与Promise基础知识与实际用到注意的问题,将通过很多代码实例进行说明,两个实例代码是setDelay和setDelaySecond. tips:本文系原创转自我的博 ...
- AsyncLocal 与 async await
大家来看一张图 先猜猜看为什么会这样 关于async await的原理 建议查看 https://blog.csdn.net/brook_shi/article/details/50803957 这篇 ...
- How Javascript works (Javascript工作原理) (四) 事件循环及异步编程的出现和 5 种更好的 async/await 编程方式
个人总结: 1.讲解了JS引擎,webAPI与event loop合作的机制. 2.setTimeout是把事件推送给Web API去处理,当时间到了之后才把setTimeout中的事件推入调用栈. ...
- 这一次搞懂SpringBoot核心原理(自动配置、事件驱动、Condition)
@ 目录 前言 正文 启动原理 事件驱动 自动配置原理 Condition注解原理 总结 前言 SpringBoot是Spring的包装,通过自动配置使得SpringBoot可以做到开箱即用,上手成本 ...
- promise 的基本概念 和如何解决js中的异步编程问题 对 promis 的 then all ctch 的分析 和 await async 的理解
* promise承诺 * 解决js中异步编程的问题 * * 异步-同步 * 阻塞-无阻塞 * * 同步和异步的区别? 异步;同步 指的是被请求者 解析:被请求者(该事情的处理者)在处理完事情的时候的 ...
- 进阶篇:以IL为剑,直指async/await
接上篇:30分钟?不需要,轻松读懂IL,这篇主要从IL入手来理解async/await的工作原理. 先简单介绍下async/await,这是.net 4.5引入的语法糖,配合Task使用可以非常优雅的 ...
- 仿async/await(一)and Gulp:新一代前端构建利器
NET 4.5的async/await真是个神奇的东西,巧妙异常以致我不禁对其实现充满好奇,但一直难以窥探其门径.不意间读了此篇强文<Asynchronous Programming in C# ...
随机推荐
- 从零开始的react入门教程(一),让我们从hello world开始
壹 ❀ 引 按照之前的计划,从这个月开始,我将由浅至深更新一些react相关的技术博文.由于我目前也是react新手一名,所以文章本质上也算自己学习历程的记录,倘若这些文章能帮助到一些人那就再好不过了 ...
- NC17871 CSL分苹果
题目链接 题目 题目描述 CSL手上有n个苹果,第i个苹果的质量是wi,现在他想把这些苹果分给他的好朋友wavator和tokitsukaze.但是CSL为了不让他们打架,根据质量决定尽量地均分成两堆 ...
- linux下docker安装与初始
1 docker的安装与使用初识 1 docker的安装 # step 1: 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-persi ...
- 【LeetCode递归】括号生成,使用dfs
括号匹配 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合. 示例 1: 输入:n = 3 输出:["((()))","(() ...
- ZYNQ 裸机模式下修改默认uart端口
## 背景 调试ZYNQ 裸机code, 调用 printf()后在UART端口无法看到打印信息输出,查看原理图后发现,板子用的UART 1作为默认串口调试接口,UART 0分配给了RS485使用,因 ...
- 【Azure 存储服务】MP4视频放在Azure的Blob里面,用生成URL在浏览器中打开之后,视频可以正常播放却无法拖拽视频的进度
问题描述 把MP4视频放在Azure的Blob里面,用生成URL在浏览器中打开之后,视频可以正常播放却无法拖拽视频的进度,这是什么情况呢? 问题解答 因为MP4上传到Azure Blob后,根据公开的 ...
- 【Azure Redis 缓存】Azure Cache for Redis 服务的导出RDB文件无法在自建的Redis服务中导入
问题描述 使用微软云的Redis服务,导出它的RDB文件后,想把数据恢复到本地自建的Redis服务中,发现出现如下错误: 15000:S 21 Jun 08:14:11.199 * Retrying ...
- 【Azure 应用服务】App Service与Application Gateway组合使用时发生的域名跳转问题如何解决呢?
问题描述 为App Service配置了应用服务网关(Application Gateway),并且为Application Gateway配置了自定义域名,通过浏览器访问时,出现域名跳转问题,由自定 ...
- 【Azure 事件中心】如何查看事件中心的消息中具体报文内容呢?
问题描述 如何查看事件中心的消息中具体报文内容呢? 问题解答 正常情况是通过 Event Hub 的消费端获取消息进行处理查看,但是没有客户端代码的情况下,也可以通过微软的默认客户端Service B ...
- .NET 全能 Cron 表达式解析库(支持 Cron 所有特性)
前言 今天大姚给大家分享一个.NET 全能 Cron 表达式解析类库,支持 Cron 所有特性:TimeCrontab. Cron表达式介绍 Cron表达式是一种用于配置定时任务的时间表达式.它由一系 ...