javascript异步编程之generator(生成器函数)与asnyc/await语法糖
Generator 异步方案
相比于传统回调函数的方式处理异步调用,Promise
最大的优势就是可以链式调用解决回调嵌套的问题。但是这样写依然会有大量的回调函数,虽然他们之间没有嵌套,但是还是没有达到传统同步代码的可读性。如果以下面的方式写异步代码,它是很简洁,也更容易阅读的。
// like sync mode
try{
const value1 = ajax('/api/url1')
console.log(value1)
const value2 = ajax('/api/url1')
console.log(value2)
const value3 = ajax('/api/url1')
console.log(value3)
const value4 = ajax('/api/url1')
console.log(value4)
const value5 = ajax('/api/url1')
console.log(value5)
}catch(err){
console.log(err)
}
在ES2015
提供了生成器函数(Generator Function)
它与普通函数的语法差别在于,在function
语句之后和函数名之前,有一个“*”作为生成器函数的标示符。
在我们去调用生成器函数的时候他并不会立即去执行这个函数,而是会得到一个生成器对象,直到我们手动调用对象的next
方法,函数体才会开始执行,我们可以使用关键字yield
去向外返回一个值,我们可以在next
方法的返回值中去拿到这个值。另外再返回的属性中还有一个done
关键字来表示生成器是否执行完了,
yield
不会像return
一样去结束函数的执行,只是暂停函数的执行,直到外接下一次调用next
方法时才会继续从yield
位置往下执行
function * foo () {
console.log('start')
yield 'foo'
}
const generator = foo()
const result = generator.next()
调用next
方法的时候传入了参数的话,所传入的参数会作为yield
关键字的返回值
function * foo () {
console.log('start')
// 我可以在这里接收next传入的参数
const res = yield 'foo'
console.log(res) // 这是我传入的参数
}
const generator = foo()
const result = generator.next('这是我传入的参数')
console.log(result) // { value: 'foo', done: false }
如果我们调用了生成器函数的throw
方法,这个方法会给生成器函数内部抛出一个异常
function * foo () {
console.log('start')
// 我可以在这里接收next传入的参数
try {
const res = yield 'foo'
console.log(res) // 这是我传入的参数
} catch (err) {
console.log(err.message) // 抛出错误
}
}
const generator = foo()
const result = generator.next('这是我传入的参数')
console.log(result)
generator.throw(new Error('抛出错误'))
利用生成器函数和Promise
来实现异步编程的体验
function ajax(url) {
return new Promise((resove, reject) => {
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
// 新方法可以直接接受一个j对象
xhr.responseType = 'json'
xhr.onload = function () {
if (this.status === 200) {
resove(this.response)
} else {
reject(new Error(this.statusText))
}
}
xhr.send()
})
}
function* main() {
const user1 = yield ajax('/json1.json')
console.log(user1)
const user2 = yield ajax('/json2.json')
console.log(user2)
const user3 = yield ajax('/json3.json')
console.log(user3)
}
const g = main()
const result = g.next()
result.value.then(data => {
const result2 = g.next(data)
if (result2.done) return
result2.value.then(data2 => {
const result3 = g.next(data2)
if (result3.done) return
result3.value.then(data3 => {
g.next(data3)
})
})
})
很明显生成器的执行器可以使用递归的方式去调用
const g = main()
function handleResult(result) {
if (result.done) return
result.value.then(data => {
handleResult(g.next(data))
}, err => {
g.throw(err)
})
}
handleResult(g.next())
生成器函数的调用其实都是差不多的,所以我们可以写一个比较通用的执行器
function co(generator) {
const g = generator()
function handleResult(result) {
if (result.done) return
result.value.then(data => {
handleResult(g.next(data))
}, err => {
g.throw(err)
})
}
handleResult(g.next())
}
co(main)
当然这样的执行器在社区中已经有一个比较完善的库了co。这种co
的方案在2015
年之前是特别流行的,后来在出了async/await
语法糖之后,这种方案相对来讲就没有那么普及了。使用generator
这种方法最明显的变化就是异步调用回归到扁平化了
async/await
有了generator
之后js
异步编程基本上与同步代码有类似的体验了,但是使用generator
这种异步方案还需要自己手动去写一个执行器函数,会比较麻烦。在ES2017
的版本中新增了一个叫做async
的函数,它同样提供了这种扁平化的编程体验,并且是语言层面的标准的异步编程语法。其实async
函数就是生成器函数更方便的语法糖,所以语法上给generator
函数是类似的。
async function main() {
try {
const user1 = await ajax('/json1.json')
console.log(user1)
const user2 = await ajax('/json2.json')
console.log(user2)
const user3 = await ajax('/json3.json')
console.log(user3)
} catch (error) {
console.log(error)
}
}
main()
async
函数返回一个Promise
对象,更利于对整体代码控制
promise.then(() => {
console.log('all completed')
}).catch(err => {
console.log(err)
})
原文地址: https://kspf.xyz/archives/21
更多内容微信公众号搜索充饥的泡饭
小程序搜一搜开水泡饭的博客
javascript异步编程之generator(生成器函数)与asnyc/await语法糖的更多相关文章
- 异步编程之Generator(1)——领略魅力
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- Javascript异步编程之setTimeout与setInterval详解分析(一)
Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程(注意:特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛 ...
- 异步编程之Generator(2)——剖析特性
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- 【转】Javascript异步编程之setTimeout与setInterval
Javascript异步编程之setTimeout与setInterval 转自:http://www.tuicool.com/articles/Ebueua 在谈到异步编程时,本人最主要会从以下三个 ...
- (翻译)异步编程之Promise(1):初见魅力
原文:https://www.promisejs.org/ by Forbes Lindesay 异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2) ...
- 异步编程之Promise(3):拓展进阶
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- 异步编程之Promise(2):探究原理
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- 异步编程之co——源码分析
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- JavaScript模块化编程之AMD - requireJS基础使用
JavaScript模块化编程之AMD requireJS基础使用 标签(空格分隔): JavaScript 参考文章 AMD规范 AMD是"Asynchronous Module Defi ...
随机推荐
- 新一代分布式实时流处理引擎Flink入门实战操作篇
@ 目录 安装部署 安装方式 Local(Standalone 单机部署) Standalone部署 Standalone HA部署 Flink On Yarn演示案例 概述 会话(Session)模 ...
- [HDU6057] Kanade‘s convolution (FWT)
题面 出自HDU6057 给你两个数列 A [ 0... 2 m − 1 ] A[0...2^m-1] A[0...2m−1] 和 B [ 0... 2 m − 1 ] B[0...2^m-1] B[ ...
- Crash的数字表格 (莫比乌斯反演)
Crash的数字表格 Description 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b)表示能同时被a和b ...
- Typora的破解
Typora是什么? Typora是一款支持实时预览的Markdown文本编辑器.支持即时渲染技术,这也是与其他Markdown编辑器最显著的区别.即时渲染使得你写Markdown就想是写Word文档 ...
- Spring集成测试
Spring 集成测试 需要再类的头部加入 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath ...
- 使用ESP8266nodeMCU 向微信推送模板数据
使用HTTPS协议向微信公众号推送消息,(使用ESP8266的低成本实现) 前几天被朋友问到这个东西的实现方式,花了一下午时间研究一下,特此记录.没有排版比较乱. 一丶前往微信公众平台注册微信微信公众 ...
- C#非托管泄漏中HEAP_ENTRY的Size对不上是怎么回事?
一:背景 1. 讲故事 前段时间有位朋友在分析他的非托管泄漏时,发现NT堆的_HEAP_ENTRY 的 Size 和 !heap 命令中的 Size 对不上,来咨询是怎么回事? 比如下面这段输出: 0 ...
- 全志H616基于官方外设开发-蜂鸣器
#include <stdio.h> #include <wiringPi.h> #include <unistd.h> #define BEEP 0 //设置针脚 ...
- 管理数据库的神器:DBeaver
转载自:https://mp.weixin.qq.com/s/oqEAZNk-TorqRUocav27Ew GitHub地址:https://github.com/dbeaver/dbeaver 软件 ...
- k8s中安装rabbitmq集群
官方文档地址:https://www.rabbitmq.com/kubernetes/operator/quickstart-operator.html 要求 1.k8s版本要1.18及其以上 2.能 ...