首页 > 编程语言 >javascript异步编程之generator(生成器函数)与asnyc/await语法糖

javascript异步编程之generator(生成器函数)与asnyc/await语法糖

时间:2022-11-01 23:00:14浏览次数:73  
标签:const log generator javascript 生成器 next console

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​

标签:const,log,generator,javascript,生成器,next,console
From: https://blog.51cto.com/u_12095767/5815072

相关文章

  • javascript异步编程之generator(生成器函数)与asnyc/await语法糖
    Generator异步方案相比于传统回调函数的方式处理异步调用,Promise最大的优势就是可以链式调用解决回调嵌套的问题。但是这样写依然会有大量的回调函数,虽然他们之间没有嵌......
  • day06-JavaScript03
    JavaScript0311.DOM官方文档:https://www.w3school.com.cn/js/js_htmldom.asp基本介绍:DOM全称是DocumentObjectModel,文档对象模型。当网页被加载时,浏览器会......
  • JavaScript重要知识点整理
    (一)JavaScript简介(二)语法基础(三)流程控制(四)初识函数(补充)对象(五)字符串对象(六)数组对象(七)时间对象(八)数学对象(九)DOM基础(十)DOM进阶(十一)事件基础(十二)事件进阶(十三)window对象(十四)docu......
  • Javascript笔记 - 数组常用方法
    数组目录数组1.数组基础2.常用数组方法输出:toString()增删:push()、pop()、shift()、unshift()提取:splice()、concat()、slice()3.数组排序sort()reverse()4.数组迭代......
  • Javascript笔记 - JS中的函数
    函数目录函数1.函数的声明与定义2.方法3.作用域全局作用域函数作用域声明提前4.构造函数instanceof5.call()和apply()6.this和argumentsthisarguments1.函数的......
  • JavaScript笔记 - JS和html代码的结合方式
    JavaScript和html代码的结合方式方式一在head标签或body标签中,使用script标签来书写JavaScript代码<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF......
  • Javascript笔记 - JS中的变量
    变量目录变量1.变量基础2.强制类型转换3.关系运算1.变量基础JS是一门弱类型语言,这意味变量的类型不是固定的,变量可以随时从一种类型转换为另一种类型vari=1;......
  • javascript
    javascript快速入门内部标签<script>alert("helloword!");</script>外部引入<scriptsrc=""></script>基本语法入门数据类型数据、文本、图形、音......
  • Javascript笔记 - JS中的对象
    对象目录对象1.对象的声明与定义2.原型对象3.枚举对象中属性特殊属性值in运算符hasOwnProperty方法for...in语句1.对象的声明与定义显式声明对象并逐个定义属性......
  • JavaScript知识体系(脑图)
    参考书目:《从0到1JavaScript快速上手》(莫振杰著)以下为个人读后参照此书所做,便于今后个人以及对JavaScript感兴趣的小伙伴对JavaScript有一个更系统的认识。......