2803. 生成器函数
2025年11月12日大约 3 分钟
2803. 生成器函数
function* factorial(n) {
if(n===0) return 1;
let result = 1;
for (let i = 1; i <= n; i++) {
result *= i;
yield result; // 每次产出 i! 的值
}
}✅ 什么是生成器?
生成器函数是 ES6 引入的一种函数类型,可以 在执行过程中暂停,并在之后继续执行。这种特性使其非常适合实现迭代器、异步控制流、惰性求值等场景。
🧬 语法基础
function* generatorName([param1, param2, ...]) {
yield value1;
yield value2;
return finalValue;
}function*:星号表示这是一个生成器函数
yield:关键字,用来“产出”值并暂停执行
.next():继续执行到下一个 yield
return 不会在 for...of 中被遍历到
yield 可以接收值和产出值
调用生成器函数不会立即执行,必须通过 .next() 启动
yield*(委托另一个生成器)
function* inner() {
yield "A";
yield "B";
}
function* outer() {
yield "Start";
yield* inner(); // 委托 inner 的产出
yield "End";
}
for (const val of outer()) {
console.log(val); // Start, A, B, End
}yield 可传值
function* dialogue() {
const answer1 = yield "你是谁?";
const answer2 = yield "你从哪里来?";
return `你好,${answer1},来自${answer2}`;
}
const gen = dialogue();
console.log(gen.next().value); // "你是谁?"
console.log(gen.next("小明").value); // "你从哪里来?"
console.log(gen.next("北京").value); // "你好,小明,来自北京"实现自定义迭代器
const iterable = {
*[Symbol.iterator]() {
yield 10;
yield 20;
yield 30;
}
};
for (const val of iterable) {
console.log(val); // 10, 20, 30
}依赖函数队列(重试,超时)
const taskFns = [
async () => {
console.log("任务1开始");
return "结果1";
},
async (prevResult) => {
console.log("任务2接收到:", prevResult);
if (Math.random() < 0.7) throw new Error("任务2随机失败");
return prevResult + " → 结果2";
},
async (prevResult) => {
console.log("任务3接收到:", prevResult);
return prevResult + " → 结果3";
}
];
function* retryableTaskQueue(taskFns, maxRetries = 3, delay = 1000) {
let lastResult = undefined;
for (let i = 0; i < taskFns.length; i++) {
let attempt = 0;
while (attempt < maxRetries) {
try {
const result = yield taskFns[i](lastResult); // 将前一个结果传入
lastResult = result; // 保存供下一个用
break; // 当前任务成功,进入下一个任务
} catch (err) {
attempt++;
console.warn(`任务 ${i + 1} 第 ${attempt} 次尝试失败:`, err.message);
if (attempt >= maxRetries) {
throw new Error(`任务 ${i + 1} 已超过最大重试次数`);
}
yield new Promise(res => setTimeout(res, delay)); // 等待后重试
}
}
}
return lastResult; // 最后一个任务的结果
}
async function run(gen) {
const iterator = gen();
async function step(nextFn, value) {
try {
const { value: yielded, done } = nextFn.call(iterator, value);
if (done) return yielded;
const resolved = yielded instanceof Promise ? await yielded : yielded;
return step(iterator.next, resolved);
} catch (err) {
return step(iterator.throw, err);
}
}
return step(iterator.next);
}
run(() => retryableTaskQueue(taskFns, 3, 1000))
.then(result => console.log("✅ 所有任务完成:", result))
.catch(err => console.error("❌ 有任务失败:", err.message));题目要点
「2803. 生成器函数」属于 API 行为建模题,关键在于把题面语义转成可验证的函数契约与状态约束。
思路拆解
- 提取题目的显式规则与隐式规则(返回值、this 语义、副作用范围)。
- 用最小可行实现覆盖主路径,再逐步补齐异常路径。
- 对原型扩展题优先保证幂等性与可组合性,避免污染全局行为。
复杂度分析
- 时间复杂度:通常由单次调用的内部循环或字符串/数组操作决定。
- 空间复杂度:重点观察闭包捕获、中间数组与临时对象创建开销。
边界与测试
- 非法参数、缺省参数、类型不匹配。
- 多次调用、链式调用、上下文切换。
- 与原生行为对齐性(是否符合语言规范直觉)。
工程实践
将“语义规则”写成注释清单并配套最小测试样例,比只给实现代码更利于长期复用。
总结
建模题的沉淀价值在于形成可迁移的语义模板:先定契约,再写实现,最后用反例校验边界。
