在JavaScript中,生成器(Generator)是ES6引入的一种新的数据类型,它允许你定义一个函数,该函数可以根据需要一次返回(产出)一个值,而不是立即返回一个最终值。这使得它可以在需要时生成值,这对于处理大量数据或需要“懒加载”的场景特别有用。
生成器函数的定义与普通函数非常相似,但它使用了*
标识,并且使用yield
关键字返回值。
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
当你调用一个生成器函数时,它不会立即执行,而是返回一个迭代器对象。使用这个对象的next()
方法可以从生成器中获取下一个值。
// 创建一个简单的生成器
const gen = simpleGenerator();
// 获取生成器的第一个值并打印
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 }
每次调用next()
都会执行生成器函数,直到遇到下一个yield
,然后暂停执行并返回yield
后的值。当没有更多的值可以yield
时,done
属性为true
。
除了从生成器返回值,你还可以发送值回生成器。这是通过在next()
调用中传递一个参数来实现的:
// 定义一个可以接收输入的生成器函数
function* generatorWithInput() {
const input = yield; // 从外部接收一个值,并赋值给input
console.log(input); // 打印接收到的值
}
// 创建生成器实例
const gen = generatorWithInput();
// 启动生成器,此时它等待输入
gen.next();
// 向生成器传入字符串'Hello!',并继续执行
gen.next('Hello!'); // 输出: Hello!
// 定义一个名为rootSaga的生成器函数
function* rootSaga() {
yield { type: 'PUT', action: { type: "ADD" } }; // 发送一个PUT类型的动作,动作类型为ADD
yield new Promise(resolve => setTimeout(resolve, 3000)) // 等待3秒的Promise
yield { type: 'PUT', action: { type: "MINUS" } }; // 再次发送一个PUT类型的动作,动作类型为MINUS
}
// 定义一个执行saga的函数
function runSaga(saga) {
const it = saga(); // 创建生成器实例
function next() { // 定义一个处理生成器值的递归函数
const { done, value: effect } = it.next(); // 获取生成器的下一个值
if (!done) { // 如果生成器没有完成
if (effect instanceof Promise) { // 如果值是一个Promise
effect.then(next); // 等待Promise完成后继续
} else if (effect.type === 'PUT') { // 如果值是一个PUT类型的动作
console.log(`向仓库派发一个动作${JSON.stringify(effect.action)}`); // 打印派发的动作
next(); // 继续执行
} else { // 其他情况
next(); // 直接继续执行
}
}
}
next(); // 启动递归函数
}
// 运行rootSaga生成器函数
runSaga(rootSaga);
// 定义一个名为gen的生成器函数
function * gen(){
yield 1; // 产出值1
yield 2; // 产出值2
yield 3; // 产出值3
}
// 创建gen生成器的迭代器
let it = gen();
// 打印迭代器的[Symbol.iterator]属性,这将展示生成器对象的迭代器方法
console.log(it[Symbol.iterator]);
// 获取迭代器的第一个值
let r1 = it.next();
console.log(r1); // 输出:{ value: 1, done: false }
// 结束生成器的执行并返回一个给定的值
//let r2 = it.next();
//let r2 = it.throw();
let r2 = it.return();
console.log(r2); // 输出:{ value: undefined, done: true }
// 试图获取迭代器的下一个值,但生成器已经结束
let r3 = it.next();
console.log(r3); // 输出:{ value: undefined, done: true }
// 再次尝试获取迭代器的下一个值
let r4 = it.next();
console.log(r4); // 输出:{ value: undefined, done: true }
// 导入events模块中的EventEmitter类
let EventEmitter = require('events');
// 创建一个EventEmitter实例
let e = new EventEmitter();
// 为“click”事件注册一个只会被调用一次的监听器
e.once('click',(data)=>{
console.log('clicked',data); // 打印“clicked”和传递的数据
});
// 触发“click”事件并传入字符串'data'作为数据
e.emit('click','data'); // 输出:clicked data
// 再次尝试触发“click”事件,但因为我们使用了.once注册监听器,所以这次不会有输出
e.emit('click','data');