javascript中的迭代器和生成器是ES6引入的重要特性,它们为数据遍历和异步流程控制提供了更优雅的解决方案。迭代器定义了遍历数据集合的标准接口,生成器则是能够暂停执行的函数,二者结合可以大幅简化复杂的异步操作逻辑。

什么是javascript迭代器
迭代器是一个对象,它提供了一个next()方法,每次调用该方法都会返回一个包含value和done两个属性的对象。value表示当前遍历到的值,done表示是否已经遍历完成。只要一个对象实现了迭代器协议,就可以被for...of循环遍历。
下面是一个自定义迭代器的简单示例:
// 自定义一个可迭代的对象
const myIterable = {
data: [1, 2, 3],
// 实现Symbol.iterator方法,返回迭代器对象
[Symbol.iterator]() {
let index = 0;
const self = this;
return {
next() {
if (index < self.data.length) {
return { value: self.data[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
};
// 使用for...of遍历自定义迭代对象
for (const item of myIterable) {
console.log(item); // 依次输出1、2、3
}
什么是javascript生成器
生成器是一种特殊的函数,在函数声明时需要在function关键字后面加一个星号*,函数内部可以使用yield关键字暂停执行,返回一个值。调用生成器函数不会立即执行函数体,而是返回一个生成器对象,这个对象本身就是一个迭代器,因此可以直接使用for...of遍历。
生成器的基础使用示例:
// 定义生成器函数
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
// 获取生成器对象
const gen = numberGenerator();
// 手动调用next方法
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
// 也可以用for...of遍历
for (const num of numberGenerator()) {
console.log(num); // 依次输出1、2、3
}
生成器如何简化异步操作
传统的异步操作如果使用回调函数或者Promise的链式调用,当逻辑复杂时会出现回调嵌套或者长链式调用的问题,代码可读性较差。生成器配合Promise可以让异步代码看起来像同步代码一样,大幅提升可读性。
我们可以使用生成器来暂停异步操作的执行,等待Promise状态变更后再继续执行下一步。下面是一个模拟异步请求的生成器示例:
// 模拟异步请求函数,返回Promise
function mockAsyncRequest(url) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`从${url}获取到的数据`);
}, 1000);
});
}
// 定义生成器函数处理异步流程
function* asyncTaskGenerator() {
console.log('开始第一个请求');
const result1 = yield mockAsyncRequest('https://ipipp.com/api/data1');
console.log(result1); // 1秒后输出:从https://ipipp.com/api/data1获取到的数据
console.log('开始第二个请求');
const result2 = yield mockAsyncRequest('https://ipipp.com/api/data2');
console.log(result2); // 再1秒后输出:从https://ipipp.com/api/data2获取到的数据
return '所有异步任务完成';
}
// 生成器执行器,自动执行生成器中的异步任务
function runGenerator(gen) {
const generator = gen();
function handleResult(result) {
if (result.done) {
return result.value;
}
// 如果result.value是Promise,等待其完成后再继续执行生成器
return result.value.then((value) => {
return handleResult(generator.next(value));
});
}
return handleResult(generator.next());
}
// 执行生成器任务
runGenerator(asyncTaskGenerator).then((finalResult) => {
console.log(finalResult); // 输出:所有异步任务完成
});
上面的代码中,生成器函数asyncTaskGenerator里的异步操作看起来和同步代码几乎一样,没有嵌套的回调,也没有长长的Promise链。执行器runGenerator负责自动推进生成器的执行,当遇到yield后面的Promise时,会等待Promise完成后再把结果传给下一个next调用,让生成器继续执行。
二者核心区别总结
为了更清晰地理解迭代器和生成器的差异,我们可以通过下面的表格对比二者的核心特性:
| 对比项 | 迭代器 | 生成器 |
|---|---|---|
| 定义方式 | 手动实现next方法和Symbol.iterator接口 | 使用function*定义,内部用yield暂停执行 |
| 返回值 | 包含value和done的对象 | 返回生成器对象,本身是迭代器 |
| 执行控制 | 只能被动调用next获取下一个值 | 可以主动通过yield暂停,也可以向生成器传值 |
| 典型用途 | 自定义数据集合的遍历逻辑 | 简化异步流程、生成惰性序列数据 |
实际开发中的注意事项
在使用生成器处理异步操作时,需要注意yield后面跟的表达式必须是Promise实例,否则执行器无法正确等待其完成。另外,生成器函数内部的错误需要通过generator.throw方法抛出,才能在生成器内部被捕获,和普通的同步函数错误处理逻辑略有不同。
现在很多开发者会使用async/await语法,它其实是生成器处理异步的语法糖,底层原理和生成器配合Promise的逻辑一致,但是语法更加简洁。理解生成器的工作方式,也能帮助我们更好地掌握async/await的使用逻辑。
javascriptiteratorgenerator异步操作修改时间:2026-07-16 12:36:30