当前位置:首页 >百科 >JavaScript 中的生成器有什么用? 而且是生成什用 async/awiatcan

JavaScript 中的生成器有什么用? 而且是生成什用 async/awiatcan

2024-06-14 02:38:48 [百科] 来源:避面尹邢网

JavaScript 中的生成什用生成器有什么用?

作者:佚名 开发 前端 今天我们要讲的是JavaScript中一个不太常用的Generator语法。我很少看到有人在实际项目开发中使用它。生成什用

今天我们要讲的生成什用是JavaScript中一个不太常用的Generator语法。我很少看到有人在实际项目开发中使用它。生成什用 

JavaScript 中的生成器有什么用? 而且是生成什用 async/awiatcan

可能是生成什用因为它的语法比较复杂,而且是生成什用 async/awiatcan ,所以人们很少使用它。生成什用然而,生成什用Generatorit 仍然是生成什用。

JavaScript 中的生成器有什么用? 而且是生成什用 async/awiatcan

今天我们就从基础开始练习Generator。生成什用

JavaScript 中的生成器有什么用? 而且是生成什用 async/awiatcan

Generator介绍

JavaScript GeneratorE6是生成什用引入的一种新型函数,可以生成多个值序列,生成什用可以暂停和恢复执行,生成什用使我们能够更简单、生成什用高效地实现迭代器。生成什用

如果我们看到一个函数后面跟着一个 * 符号,那么它就是一个 Generatorfunction :

function* myGenerator() {   // Generator function}

GeneratorFunctions 可以使用yield语句来定义要生成的值的序列。 

每当yield语句时,Generator函数就会暂停执行并返回一个包含当前生成值的对象,然后执行流程将暂停,直到下一次调用generator函数。 

它的返回值是一个迭代器,可以通过调用 next() 方法来获取下一个生成的值。Generator函数中的所有yield语句都执行完毕后,done属性为true,表示generator函数已经结束(这里的流程描述比较抽象,后面用实际案例来解释会更好)。

GeneratorFunctions 是 Python 首先从 Coroutine 语言中的 coroutine() 概念演变而来,然后引入到 E6 标准中,希望用它来提高 JavaScript 中处理异步编程的能力。

Generator基本语法

GeneratorFunctions 使用 function*the 关键字定义,它可以包含多个yield表达式来控制函数执行的流程:

function* myGenerator() {   yield 1;  yield 2;  yield 3;}

调用Generator函数并不执行函数内部的代码,而是返回一个迭代器对象,next()通过调用这个对象的方法来执行函数的代码,并返回yield表达式返回的值:

const myGeneratorIterator = myGenerator();console.log(myGeneratorIterator.next()); // print {  value: 1, done: false }console.log(myGeneratorIterator.next()); // print {  value: 2, done: false }console.log(myGeneratorIterator.next()); // print {  value: 3, done: false }console.log(myGeneratorIterator.next()); // print {  value: undefined, done: true }

Generator函数执行过程中,当yieldan表达式时,函数的执行会被挂起,并将表达式的值返回给调用者。 

当next()方法时,函数将从中断处继续执行;我们可以在函数中指定返回一个最终返回值,该值将被包装在包含要返回的属性的完成对象中:

function* myGenerator() {   console.log('Start');  yield 1;  console.log('Middle');  yield 2;  console.log('End');  return 'Done';}const myGeneratorIterator = myGenerator();console.log(myGeneratorIterator.next()); // print Start, {  value: 1, done: false }console.log(myGeneratorIterator.next()); // print Middle, {  value: 2, done: false }console.log(myGeneratorIterator.next()); // print End, {  value: 'Done', done: true }

生成器的高级使用

yield*表达式

Yield* 允许 Generatorus 调用另一个 Generator 函数或函数内的可迭代对象。

当 Generatora 函数到达yield*表达式时,它会暂停执行并将执行转移到另一个 Generator 函数或可迭代对象。 

执行权不会返回到原来的Generatorfunction。

function* foo() {   yield 1;  yield 2;}function* bar() {   yield* foo();  yield 3;}for (let value of bar()) {   console.log(value); // print 1, 2, 3}

在这个例子中,表达式inGenerator函数调用该函数并将其迭代结果依次返回给该函数。bar()yield* foo()foo()bar()

数据交互

在Generator函数中,可以使用yield表达式将数据返回给调用者,调用者next()可以通过Generator方法将数据传递给函数。 

这使得调用者和 Generator 函数之间能够进行数据交互。

function* foo() {   let x = yield;  yield x * 2;}let gen = foo();gen.next(); // start generatorgen.next(10); // pass 10,print 20

在这个例子中,foo()函数的next()在第一次调用该方法时会停在第一个yield语句处,等待外部传入的数据。 

然后,当next()方法时将从外部传入的数据作为yield表达式的值,然后向下执行,直到下一个yield表达式返回数据。

实际用例

异步编程

GeneratorFunctions 还可以用于实现异步编程。可以通过调用next()方法和关键字:yieldPromise来控制函数的执行状态

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/awaitof 角色很相似,下面是两种语法的一些比较:

优势:

控制流程更灵活:可以使用 Generator 函数控制异步操作的执行顺序,多个异步操作可以按顺序执行,每个操作完成后执行下一个操作,控制流程更灵活。

Generator函数的状态可以复用:Generator函数的状态可以保存在对象中,需要的时候函数可以继续执行,并且可以使用保存的状态继续异步操作。

更通用:GeneratorFunctions 可用于处理各种类型的异步操作,包括事件、回调、迭代器和 Promisemore 。

缺点:

更高的代码复杂性:使用 Generator 函数可能会增加代码的复杂性,因为需要额外的代码和处理步骤。

可读性差:对比async/await,Generator函数的语法和代码结构都比较复杂,可读性不如async/await。

控制异步进程

使用 Generatorfunctions 也非常方便。假设有一个需求场景API需要获取,所有数据准备好后进行下一步。 

此时可以使用Generator函数让这个异步控制流程更加清晰:

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 => {   // handle all data  console.log(data);});

处理大数据可以节省内存

在处理大数据集时,如果一次性将所有数据加载到内存中,会造成内存浪费和程序性能下降。 

Generator函数可以用来按需处理数据,将数据一一读取并转换,减少内存占用,提高程序性能。

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);}

实现状态机

GeneratorFunctions 也可用于实现状态机。状态机是由一组状态和状态之间的转移规则组成的数学模型,可以用来描述系统的行为和状态。 

在实际开发中,状态机可以用来处理复杂的业务逻辑,比如表单验证、工作流控制等。

使用Generator函数实现状态机的过程如下:

定义状态机的各种状态,每个状态对应一个 Generatorfunction 。

状态之间的转换是使用 Generatorfunction 的 statements.yield 实现的

调用Generator函数时,使用循环依次执行各个状态,直到状态机完成。

这是 Generator 实现的示例:

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 stateconsole.log(sm.next('middle').value); // Enter middle stateconsole.log(sm.next('end').value); // Enter end state

最后

Generator与async/await相比,语法更加复杂,需要手动控制执行过程,使用起来相对麻烦。这也是我很少看到Generatorit被使用的原因之一。

这种语法实际上并不像看上去那样简洁易懂。 

但是在做一些复杂的控制流和状态机处理的时候还是很有用的,Generator可以让我们的流程更加清晰。

责任编辑:华轩 来源: web前端开发 JavaScript开发

(责任编辑:百科)

    推荐文章
    热点阅读