async/await剖析
async/await剖析
JavaScript
是单线程的,为了避免同步阻塞可能会带来的一些负面影响,引入了异步非阻塞机制,而对于异步执行的解决方案从最早的回调函数,到ES6
的Promise
对象以及Generator
函数,每次都有所改进,但是却又美中不足,他们都有额外的复杂性,都需要理解抽象的底层运行机制,直到在ES7
中引入了async/await
,他可以简化使用多个Promise
时的同步行为,在编程的时候甚至都不需要关心这个操作是否为异步操作。
分析
首先使用async/await
执行一组异步操作,并不需要回调嵌套也不需要写多个then
方法,在使用上甚至觉得这本身就是一个同步操作,当然在正式使用上应该将await
语句放置于 try...catch
代码块中,因为await
命令后面的Promise
对象,运行结果可能是rejected
。
function promise(){
return new Promise((resolve, reject) => {
var rand = Math.random() * 2;
setTimeout(() => resolve(rand), 1000);
});
}
async function asyncFunct(){
var r1 = await promise();
console.log(1, r1);
var r2 = await promise();
console.log(2, r2);
var r3 = await promise();
console.log(3, r3);
}
asyncFunct();
async/await
实际上是Generator
函数的语法糖,如Promises
类似于结构化回调,async/await
在实现上结合了Generator
函数与Promise
函数,下面使用Generator
函数加Thunk
函数的形式实现一个与上边相同的例子,可以看到只是将async
替换成了*
放置在函数右端,并将await
替换成了yield
,所以说async/await
实际上是Generator
函数的语法糖,此处唯一不同的地方在于实现了一个流程的自动管理函数run
,而async/await
内置了执行器,关于这个例子的实现下边会详述。对比来看,async
和await
,比起*
和yield
,语义更清楚,async
表示函数里有异步操作,await
表示紧跟在后面的表达式需要等待结果。
function thunkFunct(index){
return function f(funct){
var rand = Math.random() * 2;
setTimeout(() => funct(rand), 1000)
}
}
function* generator(){
var r1 = yield thunkFunct();
console.log(1, r1);
var r2 = yield thunkFunct();
console.log(2, r2);
var r3 = yield thunkFunct();
console.log(3, r3);
}
function run(generator){
var g = generator();
var next = function(data){
var res = g.next(data);
if(res.done) return ;
// console.log(res.value);
res.value(next);
}
next();
}
run(generator);
实现
async
函数内置了执行器,能够实现函数执行的自动流程管理,通过Generator yield Thunk
、Generator yield Promise
实现一个自动流程管理,只需要编写Generator
函数以及Thunk
函数或者Promise
对象并传入自执行函数,就可以实现类似于async/await
的效果。
Generator yield Thunk
自动流程管理run
函数,首先需要知道在调用next()
方法时,如果传入了参数,那么这个参数会传给上一条执行的yield
语句左边的变量,在这个函数中,第一次执行next
时并未传递参数,而且在第一个yield
上边也并不存在接收变量的语句,无需传递参数,接下来就是判断是否执行完这个生成器函数,在这里并没有执行完,那么将自定义的next
函数传入res.value
中,这里需要注意res.value
是一个函数,可以在下边的例子中将注释的那一行执行,然后就可以看到这个值是f(funct){...}
,此时我们将自定义的next
函数传递后,就将next
的执行权限交予了f
这个函数,在这个函数执行完异步任务后,会执行回调函数,在这个回调函数中会触发生成器的下一个next
方法,并且这个next
方法是传递了参数的,上文提到传入参数后会将其传递给上一条执行的yield
语句左边的变量,那么在这一次执行中会将这个参数值传递给r1
,然后在继续执行next
,不断往复,直到生成器函数结束运行,这样就实现了流程的自动管理。
function thunkFunct(index){
return function f(funct){
var rand = Math.random() * 2;
setTimeout(() => funct(rand), 1000)
}
}
function* generator(){
var r1 = yield thunkFunct();
console.log(1, r1);
var r2 = yield thunkFunct();
console.log(2, r2);
var r3 = yield thunkFunct();
console.log(3, r3);
}
function run(generator){
var g = generator();
var next = function(data){
var res = g.next(data);
if(res.done) return ;
// console.log(res.value);
res.value(next);
}
next();
}
run(generator);
Generator yield Promise
相对于使用Thunk
函数来做流程自动管理,使用Promise
来实现相对更加简单,Promise
实例能够知道上一次回调什么时候执行,通过then
方法启动下一个yield
,不断继续执行,这样就实现了流程的自动管理。
function promise(){
return new Promise((resolve,reject) => {
var rand = Math.random() * 2;
setTimeout( () => resolve(rand), 1000);
})
}
function* generator(){
var r1 = yield promise();
console.log(1, r1);
var r2 = yield promise();
console.log(2, r2);
var r3 = yield promise();
console.log(3, r3);
}
function run(generator){
var g = generator();
var next = function(data){
var res = g.next(data);
if(res.done) return ;
res.value.then(data => next(data));
}
next();
}
run(generator);
// 比较完整的流程自动管理函数
function promise(){
return new Promise((resolve,reject) => {
var rand = Math.random() * 2;
setTimeout( () => resolve(rand), 1000);
})
}
function* generator(){
var r1 = yield promise();
console.log(1, r1);
var r2 = yield promise();
console.log(2, r2);
var r3 = yield promise();
console.log(3, r3);
}
function run(generator){
return new Promise((resolve, reject) => {
var g = generator();
var next = function(data){
var res = null;
try{
res = g.next(data);
}catch(e){
return reject(e);
}
if(!res) return reject(null);
if(res.done) return resolve(res.value);
Promise.resolve(res.value).then(data => {
next(data);
},(e) => {
throw new Error(e);
});
}
next();
})
}
run(generator).then( () => {
console.log("Finish");
});
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://segmentfault.com/a/1190000007535316
http://www.ruanyifeng.com/blog/2015/05/co.html
http://www.ruanyifeng.com/blog/2015/05/async.html
async/await剖析的更多相关文章
- 探索c#之Async、Await剖析
阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. ...
- C# 探索c#之Async、Await剖析
探索c#之Async.Await剖析 作者:蘑菇先生 出处:http://mushroom.cnblogs.com/
- c#之Async、Await剖析
c#之Async.Await剖析 探索c#之Async.Await剖析 2015-06-15 08:35 by 蘑菇先生, 1429 阅读, 5 评论, 收藏, 编辑 阅读目录: 基本介绍 基本原理剖 ...
- 聊聊多线程那一些事儿 之 五 async.await深度剖析
hello task,咱们又见面啦!!是不是觉得很熟读的开场白,哈哈你哟这感觉那就对了,说明你已经阅读过了我总结的前面4篇关于task的文章,谢谢支持!感觉不熟悉的也没有关系,在文章末尾我会列出前四 ...
- [.NET] 利用 async & await 的异步编程
利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html 目录 异步编程的简介 异 ...
- [.NET] 怎样使用 async & await 一步步将同步代码转换为异步编程
怎样使用 async & await 一步步将同步代码转换为异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6079707.html ...
- [.NET] 利用 async & await 进行异步 IO 操作
利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html 序 上次,博主 ...
- [C#] 走进异步编程的世界 - 开始接触 async/await
走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...
- [C#] 走进异步编程的世界 - 开始接触 async/await(转)
原文链接:http://www.cnblogs.com/liqingwen/p/5831951.html 走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 ...
随机推荐
- BFC与优雅降级 渐进增强——学习笔记
BFC(块级格式化上下文) BFC(Block formatting context) 直译为"块级格式化上下文". 元素的显示模式 我们前面讲过 元素的显示模式 display. ...
- php mysqli使用
连接到数据库$mysqli = new mysqli(主机,用户,密码,数据库); 选择数据库$mysqli->select_db(数据库);设置编码$mysqli->set_charse ...
- 被缠上了,小王问我怎么在 Spring Boot 中使用 JDBC 连接 MySQL
上次帮小王入了 Spring Boot 的门后,他觉得我这个人和蔼可亲.平易近人,于是隔天小王又微信我说:"二哥,快教教我,怎么在 Spring Boot 项目中使用 JDBC 连接 MyS ...
- 50个SQL语句(MySQL版) 问题十三
--------------------------表结构-------------------------- student(StuId,StuName,StuAge,StuSex) 学生表 tea ...
- Chisel3 - util - RRArbiter
https://mp.weixin.qq.com/s/GcNIFkHfa0gW0HKkKvHZEQ 循环优先级(Round Robin)仲裁器. 参考链接: https://github. ...
- Java实现 LeetCode 274 H指数
274. H指数 给定一位研究者论文被引用次数的数组(被引用次数是非负整数).编写一个方法,计算出研究者的 h 指数. h 指数的定义: "h 代表"高引用次数"(hig ...
- Java实现 洛谷 P1618 三连击(升级版)
import java.util.Arrays; import java.util.Scanner; public class Main { private static Scanner cin; p ...
- java实现 洛谷 P1464 Function
import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.S ...
- Java实现第八届蓝桥杯杨辉三角
杨辉三角 杨辉三角也叫帕斯卡三角,在很多数量关系中可以看到,十分重要. 第0行: 1 第1行: 1 1 第2行: 1 2 1 第3行: 1 3 3 1 第4行: 1 4 6 4 1 - 两边的元素都是 ...
- Linux权限管理命令chown、chgrp、umask详解
命令chown详解 命令chown,所在路径为: 可以看到,这个命令的路径为:/usr/bin/chown ,所以它的执行权限是所有用户 命令的基本功能是改变文件或目录的所有者(只有root可以进行, ...