async和await是如何实现异步编程?
目录
- 异步编程样例
- 样例解析
- 浅谈Promise如何实现异步执行
- 参考
1.异步编程样例
样例:
// 等待执行函数
function sleep(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout)
})
}
// 异步函数
async function test() {
console.log('test start')
await sleep(1000)
console.log('test end')
}
console.log('start')
test()
console.log('end')
执行结果:
start
test start
end
test end
2.样例解析
在样例代码中,test
异步函数使用了async
和await
语法,这是ES2017里面的异步编程规范。而为了在较低版本的浏览器或Node支持这种语法,其中一种解决方案是将其转化为Generator
函数和Promise
来实现。换句话说,任何的async
和await
实现的异步函数,都可以替换成Generator
函数和Promise
实现。
第一步:先将async
和await
语法替换为相应的Generator
函数,如下
// 代码结构完全一致,只是替换了对应关键字
function *test() {
console.log('test start')
yield sleep(1000)
console.log('test end')
}
第二步:为了执行Generator
函数,使用Promise
实现一个自动执行器
函数 spawn
function spawn(genF) {
return new Promise(function(resolve, reject) {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
第三步:将相应的Generator
函数和自动执行器
函数相结合,即可得最终的等价代码
function asyncTest() {
spawn(test)
}
console.log('start')
asyncTest()
console.log('end')
第四步:执行结果,与原来的一致
start
test start
end
test end
第五步:分析asyncTest
函数执行过程
- 执行到
spawn(test)
,进入spawn
函数中,创建一个Promise并返回。 - 执行到
const gen = genF()
,获取一个状态机。(Generator 函数是一个状态机,封装了多个内部状态。) - 执行到
step(function() { return gen.next(undefined); })
, 进入step
函数中。 - 执行到
next = nextF()
,next
等于gen.next(undefined)
的返回结果。- 当
gen.next(undefined)
开始执行,状态机第一次调用,直到遇到第一个yield
表达式为止,即yield sleep(1000)
,此时控制台先输出"test start",并且返回第一个状态{ value: reuslt, done: false }
, 而 reuslt等于sleep(1000)
返回的结果,其是一个Promise。
- 当
- 执行到
if(next.done)
,此时第一个状态的done
为false
,所以不执行if
语句里面,继续往下执行。 - 执行到
Promise.resolve(next.value)
,由于第一个状态的value
是一个Promise
,所以直接返回其本身,也就相当于执行sleep(1000).then(...)
,sleep函数异步等待1秒后,resolve
接受的值为undefined
,继续执行then方法。 - 执行到
step(function() { return gen.next(v); })
,此时v
为undefined
,再次进入step
函数中。 - 再次执行到
next = nextF()
,next
等于gen.next(undefined)
的返回结果。- 当
gen.next(undefined)
再次执行时,状态机第二次调用,此时Generator函数已经执行完毕,此时控制台先输出"test end",并且返回最后的状态{ value: undefined, done: true }
- 当
- 执行到
if(next.done)
,此时第一个状态的done
为true
,所以执行if
语句里面。 - 执行到
return resolve(next.value)
,此时最初的Promise成功执行。 - 至此
asyncTest
函数执行结束。
3.浅谈Promise如何实现异步执行
从上述样例解析中可以看出,我们是用Promise来实现代码的异步执行,那Promise的内部是如何实现异步执行的呢?
通过查看Promise
的源码实现,发现其异步执行是通过asap这个库来实现的。
asap
是as soon as possible
的简称,在Node和浏览器环境下,能将回调函数以高优先级任务来执行(下一个事件循环之前),即把任务放在微任务队列中执行。
宏任务(macro-task)和微任务(micro-task)表示异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。
用法:
asap(function () {
// ...
});
补充说明:这里提及的Promise源码并不是Node和浏览器的原生实现,是一个第三方库,仅以此为参考。
4.参考
Promise - Bare bones Promises/A+ implementation
async和await是如何实现异步编程?的更多相关文章
- .NET4.5新特性async和await修饰符实现异步编程
开篇 每一个版本的.net都会引入一些新的特性,这些特性方便开发人员能够快速实现一些功能.虽然.net版本一直在更新,但是新版本对旧版本的程序都是兼容的,在这一点上微软做的还是非常好的.每次学一个新内 ...
- python教程:使用 async 和 await 协程进行并发编程
python 一直在进行并发编程的优化, 比较熟知的是使用 thread 模块多线程和 multiprocessing 多进程,后来慢慢引入基于 yield 关键字的协程. 而近几个版本,python ...
- [.NET] 利用 async & await 的异步编程
利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html 目录 异步编程的简介 异 ...
- 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]
看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...
- 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单
一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...
- .NET4.5 异步编程 async和await
msdn介绍:https://msdn.microsoft.com/zh-cn/library/hh191443.aspx 其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行, ...
- 使用 Async 和 Await 的异步编程
来自:http://msdn.microsoft.com/library/vstudio/hh191443 异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要. 对 Web 资源 ...
- .Net 4.5 异步编程初试(async和await)
.Net 4.5 异步编程初试(async和await) 前言 最近自己在研究Asp.Net Web API.在看到通过客户端来调用Web API的时候,看到了其中的异步编程,由于自己之前没有接触过, ...
- 转:[你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单
本专题概要: 引言 同步代码存在的问题 传统的异步编程改善程序的响应 C# 5.0 提供的async和await使异步编程更简单 async和await关键字剖析 小结 一.引言 在之前的C#基础知 ...
随机推荐
- 数据库--Redis
原因: 源码是官方configure过的,但官方configure时,生成的文件有时间戳信息,所以如果你的虚拟机的时间不对,比如说是2022年,就可能会出错 解决: date -s ‘yyyy-mm- ...
- 使用NPOI将Excel表导入到数据库中
public string ExcelFile() { //指定文件路径, string fileName=@"d:\Stu.xls"; //创建一个文件流,并指定其中属性 usi ...
- Android平台接入OneNET
1. OneNET简介 中国移动物联网开放平台是由中国移动打造的PaaS物联网开放平台. 平台能够帮助开发者轻松实现设备接入与设备连接,提供综合性的物联网解决方案,实现物联网设备的数据获取,数据存储, ...
- java批量处理
最近用到Java批量处理,一次性处理多个文件夹下的多个文件,在此记录一下. 我的思路:首先要保证文件夹和文件夹下的文件的命名是有规律的,利用for循环,每次自增变量,再拼接字符串,从而得到各个文件的路 ...
- 039.集群网络-Pod和SVC网络实践
一 Pod和SVC网络 1.1 实践准备及原理 Docker实现了不同的网络模式,Kubernetes也以一种不同的方式来解决这些网络模式的挑战.本完整实验深入剖析Kubernetes在网络层是如何实 ...
- Natas1 Writeup(查看页面源码)
Natas2: 提示密码就在本页,但右键被禁用,可以使用F12或者抓包查看元素得到flag. flag:ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi 常用的查看源码方法:右键查看. ...
- Swift 4.0 高级-自定义操作符
在Swift语言中,常见的操作符有+.-.*./.>.<.==.&&.||等等,如果不喜欢,你也可以定义自己喜欢的操作符. 操作符类型 中置运算符(infix operat ...
- swagger 报 i.s.m.parameters.AbstractSerializableParameter - Illegal DefaultValue null for parameter type integer java.lang.NumberFormatException: For input string
解决 方法 添加这两个依赖....别问我有啥子用....我也不知道..能解决问题 <dependency> <groupId>io.swagger</groupId> ...
- 【WebGL】WebGL API 详解
基于 WebGL Specifications 最全面的API释疑. 类型以及对象定义 这部分内容主要定义一部分类型和数据结构. typedef unsigned long GLenum; typed ...
- vue 拖拽框架 draggable
直接使用 npm i -S vuedraggable 页面使用 <template> <div class="addProduct"> <el-d ...