Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >手写async,await 理解内部原理

手写async,await 理解内部原理

作者头像
心念
发布于 2023-01-11 13:14:26
发布于 2023-01-11 13:14:26
84000
代码可运行
举报
文章被收录于专栏:前端心念前端心念
运行总次数:0
代码可运行

前言

众所周知,async,await本质就是Generator函数的语法糖。

何为糖,吃起来比较甜的。

何为语法糖,用起来比较爽的。

async await 底层并不是新东西,只是用起来比Generator函数更舒服的api...

await在等待什么

我们先看看下面这代码,这是async await的最简单使用,await后面返回的是一个Promise对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1async function getResult() {
2    await new Promise((resolve, reject) => {
3        setTimeout(() => {
4            resolve(1);
5            console.log(1);
6        }, 3000);
7    })
8
9     console.log(2);
10}
11
12getResult()

上面代码3秒后打印结果为:

1

2

也就是说明,await后面的promise对象,没resolve()前,就一直在等待。那这个是怎么实现的呢?

原理实现

先看下面代码,输出什么?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1async function getResult() {
2    await new Promise((resolve, reject) => {
3        setTimeout(() => {
4            resolve(1);
5            console.log(1);
6        }, 1000);
7    })
8    
9
10    await new Promise((resolve, reject) => {
11        setTimeout(() => {
12            resolve(2);
13            console.log(2);
14        }, 500);
15    })
16
17    await new Promise((resolve, reject) => {
18        setTimeout(() => {
19            resolve(3);
20            console.log(3);
21        }, 100);
22    })
23
24}
25
26getResult()

没错,是输出:1,2,3

现在改用generator函数专门来实现这个效果

大聪明写法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1function* getResult(params) {
2    
3    yield new Promise((resolve, reject) => {
4        setTimeout(() => {
5            resolve(1);
6            console.log(1);
7        }, 1000);
8    })
9
10    yield new Promise((resolve, reject) => {
11        setTimeout(() => {
12            resolve(2);
13            console.log(2);
14        }, 500);
15    })
16
17    yield new Promise((resolve, reject) => {
18        setTimeout(() => {
19            resolve(3);
20            console.log(3);
21        }, 100);
22    })
23}
24const gen = getResult()
25
26gen.next();
27gen.next();
28gen.next();

最终输出:3,2,1 明显不对

因为三个promise实例同时执行了,才会出现这种问题,所以需要等第一个promise,resolve之后再执行下一个

改进版:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1
2function* getResult(params) {
3
4    yield new Promise((resolve, reject) => {
5        setTimeout(() => {
6            resolve(1);
7            console.log(1);
8        }, 1000);
9    })
10
11    yield new Promise((resolve, reject) => {
12        setTimeout(() => {
13            resolve(2);
14            console.log(2);
15        }, 500);
16    })
17
18    yield new Promise((resolve, reject) => {
19        setTimeout(() => {
20            resolve(3);
21            console.log(3);
22        }, 100);
23    })
24}
25const gen = getResult()
26
27gen.next().value.then(() => {
28    gen.next().value.then(() => {
29        gen.next();
30    });
31});

打印结果:1,2,3 这次对了

但是呢,总不能有多少个await,就要自己写多少个嵌套吧,所以还是需要封装一个函数,显然,递归实现最简单

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1function* getResult(params) {
2
3    yield new Promise((resolve, reject) => {
4        setTimeout(() => {
5            resolve(1);
6            console.log(1);
7        }, 1000);
8    })
9
10    yield new Promise((resolve, reject) => {
11        setTimeout(() => {
12            resolve(2);
13            console.log(2);
14        }, 500);
15    })
16
17    yield new Promise((resolve, reject) => {
18        setTimeout(() => {
19            resolve(3);
20            console.log(3);
21        }, 100);
22    })
23}
24const gen = getResult()
25
26function co(g) {
27    g.next().value.then(()=>{
28        co(g)
29    })
30}
31
32co(gen)

再来看看打印结果,发现了一个报错

可以发现成功执行了,但是为什么报错了?

这是因为generator方法会返回四次,最后一次的value是undefined。

而实际上返回第三次就表示已经返回done,代表结束了,所以,我们需要判断是否是已经done了,不再让它继续递归

所以可以改成这样

最终版

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1function* getResult(params) {
2
3    yield new Promise((resolve, reject) => {
4        setTimeout(() => {
5            resolve(1);
6            console.log(1);
7        }, 1000);
8    })
9
10    yield new Promise((resolve, reject) => {
11        setTimeout(() => {
12            resolve(2);
13            console.log(2);
14        }, 500);
15    })
16
17    yield new Promise((resolve, reject) => {
18        setTimeout(() => {
19            resolve(3);
20            console.log(3);
21        }, 100);
22    })
23}
24const gen = getResult()
25
26function co(g) {
27    const nextObj = g.next();
28    if (nextObj.done) {
29        return;
30    }
31    nextObj.value.then(()=>{
32        co(g)
33    })
34}
35
36co(gen)

可以看到这样就实现了。

完美,这个co其实也是大名鼎鼎的co函数的简单写法

结论

async内部就是帮我们执行了co函数,根据resolve时机自动调用Generator.next(),实现await的等待执行,啊真香

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
手写async await的最简实现(20行)
如果让你手写async函数的实现,你是不是会觉得很复杂?这篇文章带你用20行搞定它的核心。
ssh_晨曦时梦见兮
2020/04/11
1.6K0
字节前端高频手写面试题(持续更新中)1
观察者需要放到被观察者中,被观察者的状态变化需要通知观察者 我变化了 内部也是基于发布订阅模式,收集观察者,状态变化后要主动通知观察者
helloworld1024
2023/01/03
7560
async/await剖析
JavaScript是单线程的,为了避免同步阻塞可能会带来的一些负面影响,引入了异步非阻塞机制,而对于异步执行的解决方案从最早的回调函数,到ES6的Promise对象以及Generator函数,每次都有所改进,但是却又美中不足,他们都有额外的复杂性,都需要理解抽象的底层运行机制,直到在ES7中引入了async/await,他可以简化使用多个Promise时的同步行为,在编程的时候甚至都不需要关心这个操作是否为异步操作。
WindRunnerMax
2020/08/27
3520
async/await 原理及执行顺序分析
之前写了篇文章《这一次,彻底理解Promise原理》,剖析了Promise的相关原理。我们都知道,Promise解决了回调地狱的问题,但是如果遇到复杂的业务,代码里面会包含大量的 then 函数,使得代码依然不是太容易阅读。
桃翁
2019/11/08
2.1K0
如何写出一个惊艳面试官的 Promise【近 1W字】 前言源码1.Promise2.Generator3.async 和 await4.Pro
1.高级 WEB 面试会让你手写一个Promise,Generator 的 PolyFill(一段代码); 2.在写之前我们简单回顾下他们的作用; 3.手写模块见PolyFill.
火狼1
2020/05/09
7510
如何写出一个惊艳面试官的 Promise【近 1W字】
                            前言源码1.Promise2.Generator3.async 和 await4.Pro
Node理论笔记:异步编程
在JavaScript中,函数是一等公民,使用非常自由,无论是调用它,或者作为参数,或者作为返回值均可。
Ashen
2020/06/01
1.1K0
async/await 源码实现
如果你有一个这样的场景,b依赖于a,c依赖于b,那么我们只能通过promise then的方式实现。这样的的可读性就会变得很差,而且不利于流程控制,比如我想在某个条件下只走到 b 就不往下执行 c 了,这种时候就变得不是很好控制!
用户4131414
2020/03/19
1.4K0
面试官问 async、await 函数原理是在问什么?
这周看的是 co 的源码,我对 co 比较陌生,没有了解和使用过。因此在看源码之前,我希望能大概了解 co 是什么,解决了什么问题。
若川
2021/09/27
7060
Promise/async/Generator实现原理解析
笔者刚接触async/await时,就被其暂停执行的特性吸引了,心想在没有原生API支持的情况下,await居然能挂起当前方法,实现暂停执行,我感到十分好奇。好奇心驱使我一层一层剥开有关JS异步编程的一切。阅读完本文,读者应该能够了解:
Nealyang
2020/03/25
1.9K0
JavaScript 异步解决方案 async/await
异步操作一直都是 JavaScript 中一个比较麻烦的事情,从最早的 callback hell,到TJ大神的 co,再到 Promise 对象,然后ES6中的 Generator 函数,每次都有所改进,但都不是那么彻底,而且理解起来总是很复杂。
李振
2021/11/26
4300
JavaScript 的 async/await : async 和 await 在干什么
async 是“异步”的简写,而 await 可以认为是 async wait 的简写。 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。 await 只能出现在 async 函数中。
一个会写诗的程序员
2018/08/17
1K0
JavaScript 的 async/await : async 和 await 在干什么
async 函数的含义和用法
本文是《深入掌握 ECMAScript 6 异步编程》系列文章的最后一篇。 Generator函数的含义与用法 Thunk函数的含义与用法 co函数库的含义与用法 async函数的含义与用法 一、终极
ruanyf
2018/04/12
7520
async 函数的含义和用法
再谈异步
小亲冈 爱屋吉屋 前端开发工程师 按顺序完成异步操作 实际开发中,经常遇到一组异步操作,需要按照顺序完成。比如,展示页面中有上中下三个部分,每一部分通过一个接口获得数据后就展示该部分区域内容,要求这三部分要自上而下显示,避免下面部分先展示,然后上面部分突然“窜出”影响体验。 思考点 接口调用应该并行发出请求,而不是按顺序继发。 接口请求可能出现异常,每个接口的异常处理不尽相同,应该分开处理。 如果接口依次返回结果,当然可以直接展示数据。但是,如果后面部分的接口先返回结果,应该等前面接口结果返回并展示后才能展
前端黑板报
2018/01/29
5980
前端二面必会手写面试题
script标签不遵循同源协议,可以用来进行跨域请求,优点就是兼容性好但仅限于GET请求
helloworld1024
2022/12/20
6620
JavaScript异步编程:Generator与Async
JavaScript异步编程:Generator与Async 从Promise开始,JavaScript就在引入新功能,来帮助更简单的方法来处理异步编程,帮助我们远离回调地狱。 Promise是下边要讲的Generator/yield与async/await的基础,希望你已经提前了解了它。 在大概ES6的时代,推出了Generator/yield两个关键字,使用Generator可以很方便的帮助我们建立一个处理Promise的解释器。 然后,在
贾顺名
2018/06/14
1.1K0
异步多图加载这件小事儿(Promise与async)
日常开发过程中,时不时会遇到要同时预加载几张图片,并且等都加载完再干活的情况,结合 Promise 和 async/await 代码会优雅很多,但也容易遇到坑,今天就来简单聊聊。 ES5 先从最基本的 ES5 说起,基本思路就是做一个计数器,每次 image 触发 onload 就加一,达到次数后触发回调函数。 var count = 0, imgs = []; function loadImgs(imgList, cb) { imgList.forEach(function(url,
Bob.Chen
2018/05/02
2.5K0
异步多图加载这件小事儿(Promise与async)
「Async/Await」仅仅了解使用?这次我们来聊聊它是如何被实现的
这篇 Async 是如何被实现的,其实断断续续已经在草稿箱里躺了很久了。终于在一个夜黑风高的周六晚上可以给他画上一个句号。
19组清风
2022/02/28
8970
「Async/Await」仅仅了解使用?这次我们来聊聊它是如何被实现的
async原理解析
把上面代码的Generator函数 foo 可以写成 async 函数,就是这样:
木子星兮
2020/07/16
6850
co 函数库的含义和用法
======================================== 以下是《深入掌握 ECMAScript 6 异步编程》系列文章的第三篇。 Generator函数的含义与用法 Th
ruanyf
2018/04/12
1.1K0
co 函数库的含义和用法
好好学习JS异步原理
平常在工作中,我们经常与异步打交道,无论是函数节流、防抖,异步请求,都是异步操作。那么我们会经常使用setTimeout,Promise,Async/Await这三个东西。那么我们是真的了解这些api和语法糖他们的原理以及知识吗?本篇文章将从尽可能的说明白个中的原理和知识。
LamHo
2022/09/26
1.4K0
好好学习JS异步原理
相关推荐
手写async await的最简实现(20行)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档