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语法糖的更多相关文章

  1. 异步编程之Generator(1)——领略魅力

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  2. Javascript异步编程之setTimeout与setInterval详解分析(一)

    Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程(注意:特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛 ...

  3. 异步编程之Generator(2)——剖析特性

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  4. 【转】Javascript异步编程之setTimeout与setInterval

    Javascript异步编程之setTimeout与setInterval 转自:http://www.tuicool.com/articles/Ebueua 在谈到异步编程时,本人最主要会从以下三个 ...

  5. (翻译)异步编程之Promise(1):初见魅力

    原文:https://www.promisejs.org/ by Forbes Lindesay 异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2) ...

  6. 异步编程之Promise(3):拓展进阶

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  7. 异步编程之Promise(2):探究原理

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  8. 异步编程之co——源码分析

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  9. JavaScript模块化编程之AMD - requireJS基础使用

    JavaScript模块化编程之AMD requireJS基础使用 标签(空格分隔): JavaScript 参考文章 AMD规范 AMD是"Asynchronous Module Defi ...

随机推荐

  1. synchronized原理剖析

    synchronized原理剖析 并发编程存在什么问题? 1️⃣ 可见性 可见性:是指当一个线程对共享变量进行了修改,那么另外的线程可以立即看到修改后的最新值. 案例演示:一个线程A根据 boolea ...

  2. SpringBoot整合Redis实现常用功能

    SpringBoot整合Redis实现常用功能 建议大小伙们,在写业务的时候,提前画好流程图,思路会清晰很多. 文末有解决缓存穿透和击穿的通用工具类. 1 登陆功能 我想,登陆功能是每个项目必备的功能 ...

  3. n【c#】委托:delegate 学习笔记

    类似于c/c++的指针,只不过c#的委托存储的是某个方法的调用,派生子System.Delegate

  4. 【Java】学习路径49-练习:使用两个不同的线程类实现买票系统

    练习:使用两个不同的线程类实现买票系统 请创建两个不同的线程类.一个测试类以及一个票的管理类. 其中票的管理类用于储存票的数量.两个线程类看作不同的买票方式. 步骤: 1.创建所需的类 App售票线程 ...

  5. Python实现XMind测试用例快速转Excel用例

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/c2d10f21.html 你好,我是测试蔡坨坨. 今天分享一个Python编写的小工具,实现XMind测试用例转Excel用 ...

  6. Java开发学习(三十)----Maven聚合和继承解析

    一.聚合 分模块开发后,需要将这四个项目都安装到本地仓库,目前我们只能通过项目Maven面板的install来安装,并且需要安装四个,如果我们的项目足够多,那么一个个安装起来还是比较麻烦的 如果四个项 ...

  7. B树-插入

    B树系列文章 1. B树-介绍 2. B树-查找 3. B树-插入 4. B树-删除 插入 根据B树的以下两个特性 每一个结点最多有m个子结点 有k个子结点的非叶子结点拥有 k − 1 个键 可以得出 ...

  8. HCNP Routing&Switching之ARP安全

    前文我们了解了IP安全相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16652367.html:今天我们来聊一聊ARP安全相关话题: 什么是ARP? ...

  9. Django manage.py 命令详解

    manage.py 查看命令的作用的语句 C:\Users\Administrator> python manage.py help Type 'manage.py help <subco ...

  10. 海康摄像机使用GB28181接入SRS服务器的搭建步骤---源码安装的方式

    下载代码 地址:https://github.com/ossrs/srs-gb28181 https://github.com/ossrs/srs-gb28181.git 注意:使用的是含有gb281 ...