在这之前从来没有接触过generator的用法,它的写法和async/await很相似,所以看了看相关用法,以及是否能像async/await那样实现异步的链式调用。
generator跟普通函数的区别:在于generator函数是可以暂停执行的,需要暂停的地方都用yield来控制
generator的用法
//定义
function* gen() {
//后面跟的常量
yield 1
yield 2
//后面跟的函数
// yield fn2(3);
// yield fn2(4);
//后面跟的是promise
// yield fn3(5);
// yield fn3(6);
}
function fn2(num) {
return num;
}
function fn3(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num + 1);
}, 1000);
});
}
//调用
const g = gen();
console.log(g.next()); //{ value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: undefined, done: true } 到最后一步的时候done为true,这里因为gen函数没有返回值,所以value等于undefined
//若yield 后面为函数,执行结果依次为
{ value: 3, done: false }
{ value: 4, done: false }
{ value: undefined, done: true }
//若yield后面跟的是异步,则value收到的是一个promise,取值需要.then
//异步获取返回值
const g1 = g.next();
console.log("----", g1); // { value: Promise { <pending> }, done: false }
g1.value.then((res) => {
console.log(res); //6
});
const g2 = g.next();
console.log("----", g2);// { value: Promise { <pending> }, done: false }
g2.value.then((res) => {
console.log(res);//7
});
模仿async/await
//async/await的写法
async function asyncFn(){
const res=await getList()
const res2=await getNumList(res)
}
//分析
//1.async 返回的是一个promise
//2. res2会在res执行过后才会执行赋值
//3. await 返回的是promise中的resolve()或者reject()结果
//generator实现
function* gen3() {
const num1 = yield fn3(111);
const num2 = yield fn3(num1);
return 33;
}
const g3 = gen3();
let g31 = g3.next();
console.log("1", g31); // 1 { value: Promise { <pending> }, done: false }
!g31.done &&
g31.value.then((res1) => {
console.log("res1", res1); //res1 112 一秒后打出
let g32 = g3.next(res1);
console.log("2", g32);
!g32.done &&
g32.value.then((res2) => {
console.log("res2", res2); //res2 113 //2秒后
let g33 = g3.next(res2);
console.log("3", g33); // 3 { value: 33, done: true }
// !g33.done && ...
});
});
//结果:每隔一秒,就会打印出一个res
1 { value: Promise { <pending> }, done: false }
res1 112
2 { value: Promise { <pending> }, done: false }
res2 113
3 { value: 33, done: true }
//以上操作很像await的操作,但是gen并不会返回一个promise,而且链式调用需要手动去控制(万一它有几十个以上的调用呢?)
实现代码
//分析
//1.generator需要重新封装一下,使得它的返回值是一个promise (高阶函数)
//2. yield需要有链式调用的效果(自动判断)
function generatorChange(fn) {
return function () {
return new Promise((resolve, reject) => {
const g = fn();
// const next1 = g.next();
// next1.value.then()...
//最后一层的时候resolve(结果)
const go = (val, doname) => {
let result;
try {
result = g[doname](val);
} catch (error) {
return reject(error); // 报错的话会走catch,直接reject
}
let { value, done } = result;
console.log("next执行", result);
if (done) {
//结束了
return resolve(value);
} else {
//注意:value可能是一个常量,也可能是一个promise,且promise有可能是成功或者失败
return Promise.resolve(value).then(
(res) => {
console.log("next参数传递",res);
go(res, "next");
},
(err) => {
go(err, "throw");
}
);
}
};
go("", "next"); //第一次的传参不会起作用
});
};
}
//调用
const asyncFn = generatorChange(gen3);
asyncFn().then((res) => console.log(res));
注意事项
关于next的传参 :
1.next 是先执行右边的yield xx ,然后下一次next才会接收第一次的参数;
2.next只有第二次传参才会有用,第一次没用
function* gen() {
const num1 = yield fn2(11);
console.log("--此时才接参数赋值--", num1);
const num2 = yield fn2(22);
console.log("--此时才接参数赋值--", num2);
return 33;
}
const g = gen();
console.log(g.next(111));
//{ value: 11, done: false }
console.log(g.next(222));
//--此时才接参数赋值-- 222 (这里直接接收的是next(222)的值,第一次next的传参被忽略掉了)
//{ value: 22, done: false }
console.log(g.next(333));
//--此时才接参数赋值-- 333
//{ value: 33, done: true }