javascript之generator生成器函数与asnyc/await语法糖怎么使用

其他教程   发布日期:2023年11月12日   浏览次数:437

这篇文章主要讲解了“javascript之generator生成器函数与asnyc/await语法糖怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“javascript之generator生成器函数与asnyc/await语法糖怎么使用”吧!

Generator 异步方案

相比于传统回调函数的方式处理异步调用,Promise最大的优势就是可以链式调用解决回调嵌套的问题。但是这样写依然会有大量的回调函数,虽然他们之间没有嵌套,但是还是没有达到传统同步代码的可读性。如果以下面的方式写异步代码,它是很简洁,也更容易阅读的。

  1. // like sync mode
  2. try{
  3. const value1 = ajax('/api/url1')
  4. console.log(value1)
  5. const value2 = ajax('/api/url1')
  6. console.log(value2)
  7. const value3 = ajax('/api/url1')
  8. console.log(value3)
  9. const value4 = ajax('/api/url1')
  10. console.log(value4)
  11. const value5 = ajax('/api/url1')
  12. console.log(value5)
  13. }catch(err){
  14. console.log(err)
  15. }

在ES2015提供了生成器函数(Generator Function)它与普通函数的语法差别在于,在function语句之后和函数名之前,有一个“*”作为生成器函数的标示符。

在我们去调用生成器函数的时候他并不会立即去执行这个函数,而是会得到一个生成器对象,直到我们手动调用对象的next 方法,函数体才会开始执行,我们可以使用关键字yield去向外返回一个值,我们可以在next方法的返回值中去拿到这个值。另外再返回的属性中还有一个done关键字来表示生成器是否执行完了,

yield不会像return一样去结束函数的执行,只是暂停函数的执行,直到外接下一次调用next方法时才会继续从yield位置往下执行

  1. function * foo () {
  2. console.log('start')
  3. yield 'foo'
  4. }
  5. const generator = foo()
  6. const result = generator.next()

调用next方法的时候传入了参数的话,所传入的参数会作为yield关键字的返回值

  1. function * foo () {
  2. console.log('start')
  3. // 我可以在这里接收next传入的参数
  4. const res = yield 'foo'
  5. console.log(res) // 这是我传入的参数
  6. }
  7. const generator = foo()
  8. const result = generator.next('这是我传入的参数')
  9. console.log(result) // { value: 'foo', done: false }

如果我们调用了生成器函数的throw方法,这个方法会给生成器函数内部抛出一个异常

  1. function * foo () {
  2. console.log('start')
  3. // 我可以在这里接收next传入的参数
  4. try {
  5. const res = yield 'foo'
  6. console.log(res) // 这是我传入的参数
  7. } catch (err) {
  8. console.log(err.message) // 抛出错误
  9. }
  10. }
  11. const generator = foo()
  12. const result = generator.next('这是我传入的参数')
  13. console.log(result)
  14. generator.throw(new Error('抛出错误'))

利用生成器函数和Promise来实现异步编程的体验

  1. function ajax(url) {
  2. return new Promise((resove, reject) => {
  3. var xhr = new XMLHttpRequest()
  4. xhr.open('GET', url)
  5. // 新方法可以直接接受一个j对象
  6. xhr.responseType = 'json'
  7. xhr.onload = function () {
  8. if (this.status === 200) {
  9. resove(this.response)
  10. } else {
  11. reject(new Error(this.statusText))
  12. }
  13. }
  14. xhr.send()
  15. })
  16. }
  17. function* main() {
  18. const user1 = yield ajax('/json1.json')
  19. console.log(user1)
  20. const user2 = yield ajax('/json2.json')
  21. console.log(user2)
  22. const user3 = yield ajax('/json3.json')
  23. console.log(user3)
  24. }
  25. const g = main()
  26. const result = g.next()
  27. result.value.then(data => {
  28. const result2 = g.next(data)
  29. if (result2.done) return
  30. result2.value.then(data2 => {
  31. const result3 = g.next(data2)
  32. if (result3.done) return
  33. result3.value.then(data3 => {
  34. g.next(data3)
  35. })
  36. })
  37. })

很明显生成器的执行器可以使用递归的方式去调用

  1. const g = main()
  2. function handleResult(result) {
  3. if (result.done) return
  4. result.value.then(data => {
  5. handleResult(g.next(data))
  6. }, err => {
  7. g.throw(err)
  8. })
  9. }
  10. handleResult(g.next())

生成器函数的调用其实都是差不多的,所以我们可以写一个比较通用的执行器

  1. function co(generator) {
  2. const g = generator()
  3. function handleResult(result) {
  4. if (result.done) return
  5. result.value.then(data => {
  6. handleResult(g.next(data))
  7. }, err => {
  8. g.throw(err)
  9. })
  10. }
  11. handleResult(g.next())
  12. }
  13. co(main)

当然这样的执行器在社区中已经有一个比较完善的库了co。这种co的方案在2015年之前是特别流行的,后来在出了async/await语法糖之后,这种方案相对来讲就没有那么普及了。使用generator这种方法最明显的变化就是异步调用回归到扁平化了

async/await

有了generator之后js异步编程基本上与同步代码有类似的体验了,但是使用generator这种异步方案还需要自己手动去写一个执行器函数,会比较麻烦。在ES2017的版本中新增了一个叫做async的函数,它同样提供了这种扁平化的编程体验,并且是语言层面的标准的异步编程语法。其实async函数就是生成器函数更方便的语法糖,所以语法上给generator函数是类似的。

  1. async function main() {
  2. try {
  3. const user1 = await ajax('/json1.json')
  4. console.log(user1)
  5. const user2 = await ajax('/json2.json')
  6. console.log(user2)
  7. const user3 = await ajax('/json3.json')
  8. console.log(user3)
  9. } catch (error) {
  10. console.log(error)
  11. }
  12. }
  13. main()

async 函数返回一个Promise对象,更利于对整体代码控制

  1. promise.then(() => {
  2. console.log('all completed')
  3. }).catch(err => {
  4. console.log(err)
  5. })

以上就是javascript之generator生成器函数与asnyc/await语法糖怎么使用的详细内容,更多关于javascript之generator生成器函数与asnyc/await语法糖怎么使用的资料请关注九品源码其它相关文章!