换句话说,生成器函数中的return someValue
是反模式吗?
.next()
可以显示{ value: 3, done: true }
:
function* genFn() {
yield 1;
yield 2;
return 3;
}
const iter = genFn();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
但如果用作可迭代项,则不会:
function* genFn() {
yield 1;
yield 2;
return 3;
}
const iter = genFn();
console.log([...iter]);
[似乎使用return value
或不使用return
,意味着return undefined
,如果它是可迭代协议,因此也是迭代器协议,则不使用该值。
换句话说,生成器函数中的
return someValue
是反模式吗?
不,但是您应该仅在有意义时使用它。除了手动调用.next()
之外,还会产生yield*
。
function* a() {
yield 1;
yield 2;
return 3;
}
function* b() {
console.log(yield* a());
}
console.log([...b()]);
一个非常实际的例子是异步功能,其中yield
可以用作await
,而您仍然想返回一个值。当编写并非基于承诺/可移植物的相似模式时,同样的概念仍然适用。
不受JavaScript调用堆栈限制的递归,例如:
function* sillyAdd(a, b) {
return b === 0
? a
: yield sillyAdd(a + 1, b - 1);
}
const restack = f => (...args) => {
const stack = [f(...args)];
let ret = undefined;
while (stack.length !== 0) {
let {value, done} = stack[stack.length - 1].next(ret);
if (done) {
stack.pop();
ret = value;
} else {
stack.push(value);
}
}
return ret;
};
console.log(restack(sillyAdd)(2, 100000));
console.log('(it’s synchronous)');
通过在暂停的功能中保持状态进行在线解析:
function* isBalanced() {
let open = 0;
for (let c; c = yield;) {
if (c === '(') {
open++;
} else if (c === ')') {
open--;
if (open < 0) {
return false;
}
}
}
return open === 0;
}
class Parser {
constructor(generator) {
this.generator = generator();
this.generator.next();
this.done = false;
this.result = null;
}
write(text) {
if (this.done) {
return;
}
for (const c of text) {
const {value, done} = this.generator.next(c);
if (done) {
this.done = true;
this.result = value;
break;
}
}
}
finish() {
if (this.done) {
return this.result;
}
return this.generator.next().value;
}
}
const p = new Parser(isBalanced);
const chunk = '()'.repeat(1000);
for (let i = 0; i < 100; i++) {
p.write(chunk);
}
console.log(p.finish());