Generator函数设计的意思重点是把异步操作放到yeild表达式中,等调用next之后再执行,也是解决回调地狱的一种方案,其实后面es7的async await更好
生成器函数最基本的用法
// 定义个生成器函数,一般会在function后面加上一个星号来表示 let foo = function* () { for (let i = 0; i < 3; i++) { yield i } } // 将生成器函数肤质给一个变量,注意此时生成器函数内部的for循环并不会执行,可以在yield i 上面打印个log测试一下 let f = foo() // 调用f下的next()方法,最后一次因为循环结束,所以没有值被返回 console.log(f.next()) // {value:0, done:false} console.log(f.next()) // {value:1, done:false} console.log(f.next()) // {value:2, done:false} console.log(f.next()) // {value:undefined, done:true}
Generator不能被当做构造函数的方式被使用,换句话说就是不能被new,会报错foo is not a constructor
yield 关键字只能在Generator函数内部使用。例如将上面的for循环改成forEach则会因为作用域的问题报错
一个最典型的应用场景,写一个函数用来生成7得倍数
function* gen(i = 0) { while (true) { if (i % 7 === 0) { yield i } i++ } } let g = gen() console.log(g.next()) // 0 console.log(g.next()) // 7 console.log(g.next()) // 14
应用场景2:解决ajax的回调地狱。
例如有三个接口有依赖关系,常规的写法是嵌套的方式把下一个接口写到回调函数中,使用生成器可以用下面这种写法
function request(url,data = 0) { // 使用setTimeout来比喻ajax setTimeout(function () { reportData.next(data + 1) // 每次都根据上一次的返回结果去请求下一个接口 }, 1000) } function* gen() { let res1 = yield request('api/1') console.log(res1) // 1 let res2 = yield request('api/2',res1) console.log(res2) // 2 let res3 = yield request('api/3',res2) console.log(res3) // 3 } let reportData = gen() reportData.next() // 开始第一次