题目:
function* foo(num) {
let i = num || 0;
yield i ++;
yield i ++
yield i ++
}
const gen = foo(1);
gen.next() // {value: 1, done: false}
gen.next() // {value: 2, done: false}
gen.next() // {value: 3, done: true}
题目分析
- gen能调用next方法,且返回了value和done
- 说明foo执行后返回了一个对象
- 第一步:foo执行后返回的对象起码有next方法。
- 第二部:每次执行next后,都需要执行对应yield语句的运算。
怎么执行到对应的yield语句?
答案:1:采用switch case语句,模拟一个状态机,每次执行case 语句后,将状态指向在一个case语句)
2:采用全局的context.nextStep作为下次执行的指引,每次执行完当前的yield后,将 context.nextStep指向到下一个case语句。
- 第三步:每次执行yeild语句,怎么拿到上次的i,进行累加?
答案:用闭包来保存这个i,让每次调用next都能访问到i,进行++处理
- 第四步:每次执行对应的yield语句,返回对应的value和done,并将context.nextStep指向下一个case
- 第五步:到最后一次时,代表已经执行结束,不处理context.nextStep,返回的value和done都是undefined
function foo(num) {
let i = num || 0;
const context = {
nextStep: 2,
};
// 第一步:初始执行后返回一个带有next方法的对象
return {
next: function () {
// 这是一个必报,保证每次调用next都能访问到context和i
function genWarp(context) {
switch (context.nextStep) { // 根据context.nextStep状态执行对应的语句执行i ++
case 2:
context.nextStep = 4; // 第四步:每次执行对应的yield语句,返回对应的value和done,并将context.nextStep指向下一个case
return {
value: i++, // 第三步:采用闭包的形式让之后的调用都可以访问i,进行i++
done: false,
}
case 4:
context.nextStep = 6;
return {
value: i++,
done: false
}
case 6:
context.nextStep = 8;
return {
value: i++,
done: true
}
case 8: // 第五步:到最后一次时,代表已经执行结束,不处理context.nextStep,返回的value和done都是undefined
return undefined;
}
}
// 第二部: 调用genWarp传入context,context.nextStep为下次需要执行的case值
const { value, done } = genWarp(context) || {}
// 第三部返回执行genWarp(context)后的value和done
return {
value,
done,
}
}
}
}
const gen = foo(1);
gen.next() // {value: 1, done: false}
gen.next() // {value: 2, done: false}
gen.next() // {value: 3, done: true}
思考下上面的这篇代码,如果遇到其中某个yield语句是异步的代码后。怎样让下一个gen.next()在上一个gen.next()执行完成后,再执行呢?
function foo(num) {
let i = num || 0;
const context = {
nextStep: 2,
};
// 第一步:初始执行后返回一个带有next方法的对象
return {
next: function () {
// 这是一个必报,保证每次调用next都能访问到context和i
function genWarp(context) {
while (1) {
switch (context.nextStep) { // 根据context.nextStep状态执行对应的语句执行i ++
case 2:
context.nextStep = 4; // 第四步:每次执行对应的yield语句,返回对应的value和done,并将context.nextStep指向下一个case
return {
value: i++, // 第三步:采用闭包的形式让之后的调用都可以访问i,进行i++
done: false,
}
case 4:
context.nextStep = 6;
return {
value: i++,
done: false
}
case 6:
context.nextStep = 8;
return {
value: i++,
done: true
}
case 8: // 第五步:到最后一次时,代表已经执行结束,不处理context.nextStep,返回的value和done都是undefined
return undefined;
}
}
}
// 第二部: 调用genWarp传入context,context.nextStep为下次需要执行的case值
const { value, done } = genWarp(context) || {}
// 第三部返回执行genWarp(context)后的value和done
return {
value,
done,
}
}
}
}
const gen = foo(1);
gen.next() // {value: 1, done: false}
gen.next() // {value: 2, done: false}
gen.next() // {value: 3, done: true}
- genWarp内加上while(1)循环,当异步函数执行完后再将context.nextStep指向下一个状态。(只要异步函数没有执行完,就一直在这个while(1)循环内)