function* myGenerator() { // Generator 函数体 }Generator 函数可以使用 yield 语句来定义要生成的值序列。每当执行到 yield 语句时,Generator 函数会暂停执行并返回一个包含当前生成值的对象,随后执行流程被挂起,等待下一次调用生成器函数。它的返回值是一个迭代器,这个迭代器可以通过调用 next() 方法来获取下一个生成值。当 Generator 函数中所有的 yield 语句都已经执行完成后,返回的迭代器的 done 属性为 true,表示生成器函数已经结束(这里的流程描述比较抽象,我们后面用实际案例讲解会好一点)。
function* myGenerator() { yield 1; yield 2; yield 3; }调用 Generator 函数并不会执行函数内部的代码,而是返回一个迭代器对象,通过调用这个对象的 next() 方法来执行函数的代码,并返回一个由 yield 表达式返回的值:
// 堆代码 duidaima.com const myGeneratorIterator = myGenerator(); console.log(myGeneratorIterator.next()); // 输出 { value: 1, done: false } console.log(myGeneratorIterator.next()); // 输出 { value: 2, done: false } console.log(myGeneratorIterator.next()); // 输出 { value: 3, done: false } console.log(myGeneratorIterator.next()); // 输出 { value: undefined, done: true }Generator 函数在执行过程中,遇到 yield 表达式时会暂停函数的执行,并这个表达式的值返回给调用者。当再次调用 next() 方法时,函数会从暂停的地方继续执行;我们可以在函数中 return 一个最终的返回值,这个值会被包装在一个包含 value 和 done 属性的对象中返回:
function* myGenerator() { console.log('Start'); yield 1; console.log('Middle'); yield 2; console.log('End'); return 'Done'; } const myGeneratorIterator = myGenerator(); console.log(myGeneratorIterator.next()); // 输出 Start, { value: 1, done: false } console.log(myGeneratorIterator.next()); // 输出 Middle, { value: 2, done: false } console.log(myGeneratorIterator.next()); // 输出 End, { value: 'Done', done: true }
function* foo() { yield 1; yield 2; } function* bar() { yield* foo(); yield 3; } for (let value of bar()) { console.log(value); // 输出 1, 2, 3 }在这个例子中,Generator 函数 bar() 中的 yield* foo() 表达式会调用 foo() 函数并将其迭代结果依次返回给 bar() 函数。
function* foo() { let x = yield; yield x * 2; } let gen = foo(); gen.next(); // 启动生成器 gen.next(10); // 传递参数 10,输出 20在这个例子中,foo() 函数会在第一次调用 next() 方法时停止在第一个 yield 语句处,等待外部传入的数据。然后,第二次调用 next() 方法时将外部传入的数据作为 yield 表达式的值,再向下执行,直到遇到下一个 yield 表达式返回数据。
function* myGenerator() { const result1 = yield new Promise((resolve) => setTimeout(() => resolve('first'), 1000)); console.log(result1); const result2 = yield new Promise((resolve) => setTimeout(() => resolve('second'), 2000)); console.log(result2); const result3 = yield new Promise((resolve) => setTimeout(() => resolve('third'), 3000)); console.log(result3); } const generator = myGenerator(); const promise = generator.next().value; promise.then((result) => generator.next(result).value) .then((result) => generator.next(result).value) .then((result) => generator.next(result).value);看起来是不是和 async/await 的作用很像,下面是他们两种语法之间的一些对比:
2.可读性较差:相比于 async/await,Generator 函数的语法和代码结构相对较复杂,可读性不如 async/await。
function* fetchAllData() { const data1 = yield fetch('api1'); const data2 = yield fetch('api2'); const data3 = yield fetch('api3'); return [data1, data2, data3]; } function run(generator) { const iterator = generator(); function handle(iteratorResult) { if (iteratorResult.done) { return Promise.resolve(iteratorResult.value); } return Promise.resolve(iteratorResult.value) .then(res => handle(iterator.next(res))); } return handle(iterator.next()); } run(fetchAllData).then(data => { // 处理所有数据 console.log(data); });处理大数据节省内存
function* dataGenerator() { let index = 0; while (true) { yield index++; } } function* processData(data, processFn) { for (let item of data) { yield processFn(item); } } const data = dataGenerator(); const processedData = processData(data, item => item * 2); for (let i = 0; i < 500; i++) { console.log(processedData.next().value); }实现状态机
function* stateMachine() { let state = 'start'; while (true) { switch (state) { case 'start': console.log('Enter start state'); state = yield 'start'; break; case 'middle': console.log('Enter middle state'); state = yield 'middle'; break; case 'end': console.log('Enter end state'); state = yield 'end'; break; } } } const sm = stateMachine(); console.log(sm.next().value); // Enter start state console.log(sm.next('middle').value); // Enter middle state console.log(sm.next('end').value); // Enter end state