相比于传统回调的方式,Promise的去处理异步调用的优势在于链式调用解决回调嵌套过深的问题
但是大量的异步函数导致的可读性差的问题并没有得以解决
我们可以使用ES2015提供的Generator(生成器函数)

Generate的基本使用

  1. 首先生成器函数是在普通函数的基础上多了个*号
  2. 我们在调用生成器函数时并不会直接去执行这个函数,而是得到一个生成器实例对象
  3. 知道我们去手动调用生成器对象的next方法,生成器函数的函数体才会去执行
  4. 另外,我们可以在生成器内部可以随时使用yield关键词去返回一个值
  5. 我们可以在next返回对象当中的value里拿到这个值,这个返回的对象中还会有一个done属性来代表该生成器是否全部执行完毕
  6. 要注意的是yield关键词与return语句不同,它只是暂时暂停生成器函数执行,而不是立即结束这个函数的执行
  7. 当调用下一次生成器next方法时,生成器就会继续往下执行
  8. 如果在next方法中我们传入一个值,那么这个值会作为yield语句的返回值,那么我们就可以声明一个对象来接收到这个传入的值
  9. 此外我们如果使用生成器的throw方法可以让生成器内部抛出一个异常
  10. 那么这个生成器内部继续往下执行的时候我们就可以得到这个异常
  11. 这里我们使用try catch去捕获这个异常 ```json function * foo (){ console.log(‘start’)

    try { const res = yield ‘foo’ // 我们可以在生成器内部可以随时使用yield关键词去返回一个值 console.log(res) } catch (e){ console.log(e) }

    // yield关键词与return语句不同,他只是暂时暂停生成器函数执行 // 当调用下一次生成器next方法时,生成器就会继续往下执行 // 如果在next方法中我们传入一个值,我们可以在yield中得到这个传入值的 }

const generator = foo() // 此时并没有调用生成器函数,而是取得一个生成器对象

const result = generator.next() // 通过调用生成器对象的next方法,函数体才会开始执行,直到执行到yield关键词所在的位置才会停止,并把yield后面的值返回出去,这时函数才会暂停下来

console.log(result) // 返回的值中还会有一个done属性来代表该生成器是否全部执行完毕 // generator.next()

generator.throw(new Error(‘Generator error’)) // 使用生成器的throw方法可以往生成器内部抛出一个异常 // 在这种情况下继续往下执行的化,我们就可以得到这个异常

  1. <a name="3VD8O"></a>
  2. ## Generator异步方案
  3. 1. 首先我们先定义一个main的生成器函数
  4. 2. 然后在这个函数内部我们使用yield返回一个ajax调用,也就是返回了一个Promise对象,接着用声明一个users来接收这个返回值
  5. 3. 在外部我们就可以调用这个生成器函数来得到一个生成器对象实例g
  6. 4. 调用生成器对象的next方法,那么我们的main函数就会执行到第一个yield的位置,也就是会执行第一个ajax的调用
  7. 5. 此时next方法返回对象的value就是yield返回的Promise的对象,因此我们可以使用then方法去指定该Promise的回调,那么我们就可以在这个Promise的回调当中拿到Promise的执行结果
  8. 6. 我们可以通过再一次调用next把我们得到的这个data传递进去,那么我们的main函数就可以继续往下执行了
  9. 7. 而且我们传递进去的data会作为我们当前这个yield的返回值,就可以顺利拿到result
  10. 8. 以此类推,我们可以使用递归的方式不断迭代,直到返回的done属性为true
  11. ```json
  12. function ajax (url){
  13. return new Promise (function(resolve,reject){
  14. var xhr = new XMLHttpRequest()
  15. xhr.open('GET',url)
  16. xhr.responseType = 'json'
  17. xhr.onload = function(){
  18. if (this.status == 200){
  19. resolve(this.response)
  20. }else{
  21. reject(new Error(this.statusText))
  22. }
  23. }
  24. xhr.send()
  25. })
  26. }
  27. function * main () {
  28. const users = yield ajax('/users.json')
  29. console.log("users",users)
  30. const posts = yield ajax('/posts.json')
  31. console.log("posts",posts)
  32. }
  33. const g = main()
  34. const result = g.next()
  35. result.value.then(data=>{
  36. const result3 = g.next(data)
  37. if(result3.done) return
  38. result3.value.then(data=>{
  39. g.next(data)
  40. })
  41. })

Generator配合递归的方式执行异步方案