生成器函数

使用方法

  1. 调用生成器函数不会去执行函数,而是会得到一个生成器对象;
  2. 调用生成器对象的next方法才会开始执行生成器函数;
  3. 在生成器函数内部可以使用yield关键字向外返回一个值;(类似于return)
  4. 我们可以在next方法返回的对象中拿到这个值{value:’返回值’,done:false};(done表示这个生成器是否全部执行完毕)
  5. yield不像return一样立即结束而是暂停函数执行;
  6. 继续调用生成器对象的next方法才会继续执行;
  7. 调生成器对象的next方法时如果传入一个参数的话,这个值就会作为yield语句的返回值,yield的左边可以接收到这个值;
  8. 如果没有参数,yield的左边就会收到一个undefined; ```javascript // 生成器函数回顾 function* foo() { console.log(‘start’) const res = yield ‘foo’ console.log(res) }

// 调用生成器函数不会去执行函数,而是会得到一个生成器对象; const generator = foo()

// 调用生成器对象的next方法才会开始执行生成器函数; const result = generator.next() // start console.log(result) // {value: “foo”, done: false}

// yield不像return一样立即结束而是暂停函数执行; // 继续调用生成器对象的next方法才会继续执行; // 调生成器对象的next方法时如果传入一个参数的话,这个值就会作为yield语句的返回值,yield的左边可以接收到这个值; generator.next(‘bar’) // res bar

// 如果没有参数,yield的左边就会收到一个undefined; generator.next() // undefined

  1. yield关键字是在生成器函数里面 向外返回一个值,用外面的 生成器对象的next方法 获取这个值;<br />而外面的生成器对象的next方法的参数会进入到生成器函数,作为yield的结果被左边的变量接收;<br />即:yield向外返回,由next接收;next向内传入,由yield左侧接收;
  2. <a name="9wbJN"></a>
  3. ### 捕获异常
  4. 调用生成器对象的throw方法也可以让生成器函数继续往下执行,不过它的作用是向内抛入一个异常,生成器函数继续执行就会得到这个异常
  5. ```javascript
  6. function* foo() {
  7. console.log('start')
  8. try {
  9. const res = yield 'foo'
  10. // throw向内传入异常,可由内部的try catch捕获;
  11. // 因为出现异常,yield左侧的变量声明也不会执行,就直接进入catch
  12. console.log('res', res)
  13. } catch (e) {
  14. console.log(e)
  15. }
  16. }
  17. const generator = foo()
  18. const result = generator.next() // start
  19. console.log(result) // {value: "foo", done: false}
  20. generator.throw(new Error('Generator error'))
  21. // Error: Generator error

Generator 应用

发号器
使用 Generator 函数实现 iterator 方法

  1. // Generator 应用
  2. // 案例1:发号器
  3. function * createIdMaker () {
  4. let id = 1
  5. while (true) {
  6. yield id++
  7. }
  8. }
  9. const idMaker = createIdMaker()
  10. console.log(idMaker.next().value)
  11. console.log(idMaker.next().value)
  12. console.log(idMaker.next().value)
  13. console.log(idMaker.next().value)
  14. // 案例2:使用 Generator 函数实现 iterator 方法
  15. const todos = {
  16. life: ['吃饭', '睡觉', '打豆豆'],
  17. learn: ['语文', '数学', '外语'],
  18. work: ['喝茶'],
  19. [Symbol.iterator]: function * () {
  20. const all = [...this.life, ...this.learn, ...this.work]
  21. for (const item of all) {
  22. yield item
  23. }
  24. }
  25. }
  26. for (const item of todos) {
  27. console.log(item)
  28. }

Generator 配合 Promise 的异步方案

  1. // Generator 配合 Promise 的异步方案
  2. function ajax (url) {
  3. return new Promise((resolve, reject) => {
  4. var xhr = new XMLHttpRequest()
  5. xhr.open('GET', url)
  6. xhr.responseType = 'json'
  7. xhr.onload = () => {
  8. if (xhr.status === 200) {
  9. resolve(xhr.response)
  10. } else {
  11. reject(new Error(xhr.statusText))
  12. }
  13. }
  14. xhr.send()
  15. })
  16. }
  17. function * main () {
  18. try {
  19. const users = yield ajax('/api/users.json')
  20. console.log(users)
  21. const posts = yield ajax('/api/posts.json')
  22. console.log(posts)
  23. const urls = yield ajax('/api/urls11.json')
  24. console.log(urls)
  25. } catch (e) {
  26. console.log(e)
  27. }
  28. }
  29. function co (generator) {
  30. const g = generator()
  31. function handleResult (result) {
  32. if (result.done) return // 生成器函数结束
  33. result.value.then(data => {
  34. handleResult(g.next(data))
  35. }, error => {
  36. g.throw(error)
  37. })
  38. }
  39. handleResult(g.next())
  40. }
  41. co(main)
  42. // const g = generator()
  43. // const result = g.next()
  44. // result.value.then(data => {
  45. // const result2 = g.next(data)
  46. // if (result2.done) return
  47. // result2.value.then(data => {
  48. // const result3 = g.next(data)
  49. // if (result3.done) return
  50. // result3.value.then(data => {
  51. // g.next(data)
  52. // })
  53. // })
  54. // })