generator(生成器)是一个可以多次返回的函数
基本语法
generator
由function*
定义(注意多出的 * 号)
genetor初识
genetor
函数声明需要加 * 号genetor
函数的执行会返回一个对象,对象上面有一个next()
方法。genetor
函数可以分阶段执行并在阶段结束的时候返回对应的返回值。- 每个阶段的结束位置由
yield
标记(yield
类似于return
)。 - 阶段的返回值是一个对象,对象有两个属性,一个属性是
value
为yeild
后面的表达式;另一个属性为done
为一个布尔值,done
属性表示Generator
函数是否执行完毕,即是否还有下一个阶段。 - 每次调用对象的
next()
方法可以进入到下一个阶段。 genetor
函数还可以直接用for...of
进行迭代。
应用
基本使用
例如使用generator
打印斐波那契数列的前n位
function* fib(n){
let [a, b] = [1, 1];
let m = 1;
//使用循环,(一个一个地)返回对应的数列元素
while(m <= n){
yield a;
[a, b] = [b, a+b];
m++;
}
}
var t = fib(5);
console.log(t.next().value); //1
console.log(t.next().value); //1
console.log(t.next().value); //2
console.log(t.next().value); //3
console.log(t.next().value); //5
console.log(t.next().value); //undefined
//使用for...of循环迭代genetor对象
for (let i of fib(10)){
console.log(i);
}
genetor进行流程控制
genetor
可以像promise
一样解决回调地狱及其造成的代码非常难以维护的问题。
例如使用genetor
处理ajax
嵌套问题。
Promise版本
//$.ajax会返回一个promise对象
$.ajax({
url: 'data/areaList',
type: 'GET'
}).then((res) => {
//在then中返回一个新的promise
return $.ajax({
url: `data/areaDetail?arealist=${res.arealist}`,
type: 'GET'
})
}).then((res) => {
//在第二个promise变成fulfilled的时候处理数据
dealData(res.data)
})
Genetor版本
function getCallSettings1(){
$.ajax({
url: 'data/areaList',
type: 'GET',
success:(res) => {
//获取到第一层数据之后,将数据传给下一步
it.next(res.arealist)
},
error:(err) => {
it.throw(err)
}
})
}
function getCallSettings2(list){
$.ajax({
url: 'data/areaDetail?arealist=${list}',
type: 'GET',
success:(res) => {
//获取到详情信息返回出去就可以该干啥干啥了。
it.next(res.areaDetail)
},
error:(err) => {
it.throw(err)
}
})
}
function* dealData(){
var arealist = yield getCallSettings1();
var areaDetail = yield getCallSettings2(arealist);
// do something……
}
var it = dealData();
it.next() //启动生成器
Genetor和Promise结合版本
function getCallSettings1(){
return $.ajax({
url: 'data/areaList',
type: 'GET',
})
}
function getCallSettings2(list){
return $.ajax({
url: 'data/areaDetail?arealist=${list}',
type: 'GET',
})
}
function* dealData(){
var arealist = yield getCallSettings1();
var areadetail = yield getCallSettings2(arealist)
}
var it = dealData();
var pro1 = it.next().value //启动生成器并返回一个Promise
pro1.then((res) => {
//当Promise状态变成fulfilled的时候,将第一层数据传给下一步,并得到一个新的Promise
return it.next(res.arealist);
}).then((res) => {
//当新的Promise状态变成fulfilled的时候,将最终的数据传给下一步。
it.next(res.areadetail);
})
恕本菜鸟直言,结构是非常的清晰,但是Genetor
相对于Promise
有什么优势呢?思来想去还不如直接用Promise
呢。额……也可能是我太菜了