async/await剖析

JavaScript是单线程的,为了避免同步阻塞可能会带来的一些负面影响,引入了异步非阻塞机制,而对于异步执行的解决方案从最早的回调函数,到ES6Promise对象以及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内置了执行器,关于这个例子的实现下边会详述。对比来看,asyncawait,比起*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 ThunkGenerator 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剖析的更多相关文章

  1. 探索c#之Async、Await剖析

    阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. ...

  2. C# 探索c#之Async、Await剖析

    探索c#之Async.Await剖析 作者:蘑菇先生 出处:http://mushroom.cnblogs.com/

  3. c#之Async、Await剖析

    c#之Async.Await剖析 探索c#之Async.Await剖析 2015-06-15 08:35 by 蘑菇先生, 1429 阅读, 5 评论, 收藏, 编辑 阅读目录: 基本介绍 基本原理剖 ...

  4. 聊聊多线程那一些事儿 之 五 async.await深度剖析

     hello task,咱们又见面啦!!是不是觉得很熟读的开场白,哈哈你哟这感觉那就对了,说明你已经阅读过了我总结的前面4篇关于task的文章,谢谢支持!感觉不熟悉的也没有关系,在文章末尾我会列出前四 ...

  5. [.NET] 利用 async & await 的异步编程

    利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html  目录 异步编程的简介 异 ...

  6. [.NET] 怎样使用 async & await 一步步将同步代码转换为异步编程

    怎样使用 async & await 一步步将同步代码转换为异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6079707.html  ...

  7. [.NET] 利用 async & await 进行异步 IO 操作

    利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html  序 上次,博主 ...

  8. [C#] 走进异步编程的世界 - 开始接触 async/await

    走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...

  9. [C#] 走进异步编程的世界 - 开始接触 async/await(转)

    原文链接:http://www.cnblogs.com/liqingwen/p/5831951.html 走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 ...

随机推荐

  1. 使用容器化块存储OpenEBS在K3s中实现持久化存储

    作者简介 Giridhara Prasad,Mayadata Inc.首席工程师.在软件测试自动化.混沌工程(chaos engineering)方面有丰富的经验.目前,他正在研究开源混沌工程项目Li ...

  2. ie时间格式NAN-NAN-NAN

    js的日期对象可以识别的日期字符串有四种: 1.YYYY-MM-DD 2019-11-11 01:01:012.MM-DD-YYYY 11-11-2019 01:01:013.YYYY/MM/DD 2 ...

  3. Username for 'https://github.com': remote: Invalid username or password. fatal: Authentication failed for 'https://github.com/GLSmile/pythontest.git/' 问题

    使用$ git push -u origin master 进行同步时,提示输入用户名和密码,但是我输入正确的信息后,仍然 会报Username for 'https://github.com': r ...

  4. 从0开始探究vue-组件化-组件之间传值

    理解 Vue中有个非常重要的核心思想,就是组件化,组件化是为了代码复用 什么是组件化 组件化,就像一个电脑主机里的主板,有内存条的插口,有硬盘,光驱等等的插口,我们的项目,就像一个电脑主机,通过各种组 ...

  5. 工业级CC1125模块有哪些优势?主要应用领域?

    CC1125无线模块是基于 TI 的 CC1125无线收发芯片设计,是一款完整的.体积小巧的.低功耗的无线收发模块.是 TI Chipcon 推出的 ISM 频段高性能无线收发芯片之一,最大输出功率可 ...

  6. Java实现 蓝桥杯VIP 算法训练 最大质因数(暴力)

    试题 算法训练 最大质因数 问题描述 给出N个数字,求出有最大的最大质因数的那个数 输入格式 第一行:一个整数N. 接下来的N行,每行一个整数A_i,表示给出的那N个数字. 输出格式 第一行:一个整数 ...

  7. Java实现 LeetCode 643 子数组最大平均数 I(滑动窗口)

    643. 子数组最大平均数 I 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例 1: 输入: [1,12,-5,-6,50,3], k = 4 输出: 12.7 ...

  8. Java实现 蓝桥杯 算法训练 递归求二项式系数

    算法训练 6-1 递归求二项式系数值 时间限制:10.0s 内存限制:256.0MB 问题描述 样例输入 一个满足题目要求的输入范例. 3 10 样例输出 与上面的样例输入对应的输出. 数据规模和约定 ...

  9. Java实现蓝桥杯模拟递增三元组

    问题描述 在数列 a[1], a[2], -, a[n] 中,如果对于下标 i, j, k 满足 0<i<j<k<n+1 且 a[i]<a[j]<a[k],则称 a ...

  10. Java实现 蓝桥杯 算法提高 成绩排名

    试题 算法提高 成绩排名 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 小明刚经过了一次数学考试,老师由于忙碌忘记排名了,于是老师把这个光荣的任务交给了小明,小明则找到了聪明的你, ...