JavaScript 生成器函数详解:优雅处理异步任务流

这篇具有很好参考价值的文章主要介绍了JavaScript 生成器函数详解:优雅处理异步任务流。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1. 生成器函数的定义和使用

2. 暂停和恢复执行

3. 与其他语言特性的配合使用

Iterator Protocol 迭代器协议 

解构赋值 

生成器和 Promise 的组合使用 

        使用 Promise:

        使用 async/await:

委托给另外一个Generator函数


        Generators 是 JavaScript 中的一种特殊函数,它们可以暂停执行并根据需要生成多个值。通过 yield 关键字,生成器函数可以在每次被调用时产生一个新值,这使得它们非常适合处理大量数据或需要延迟计算的场景。本文将详细介绍 generators 的作用、用法以及与其他语言特性的配合使用。

1. 生成器函数的定义和使用

        生成器函数是通过一个特殊的函数关键字 function* 来定义的。在生成器函数内部,可以使用 yield 关键字来指定需要生成的值。以下是生成器函数的示例:

function* myGenerator() {
    yield 'Apple';
    yield 'Banana';
    yield 'Cherry';
}

const generator = myGenerator();

console.log(generator.next()); // 输出: { value: 'Apple', done: false }
console.log(generator.next()); // 输出: { value: 'Banana ', done: false }
console.log(generator.next()); // 输出: { value: 'Cherry', done: false }
console.log(generator.next()); // 输出: { value: undefined, done: true }

        通过调用生成器函数,我们可以获得一个生成器对象 generator。每次调用 generator.next() 都会返回一个包含 valuedone 属性的对象。

  • value 表示下一个生成的值。
  • done 表示是否还有更多的值需要生成。当所有值都被生成后,done 为 true

2. 暂停和恢复执行

        生成器函数的强大之处在于它们能够暂停和恢复执行,这意味着可以在需要时延迟计算或逐步处理大量数据,而不是一次性全部处理。以下示例展示了如何利用生成器函数处理大型数据集:

function* generateNumbers() {
    for (let i = 0; i <= 1000000; i++) {
        yield i;
    }
}

const numbersGenerator = generateNumbers();

for (let number of numbersGenerator) {
    console.log(number);
}

        在上述示例中,我们定义了一个生成器函数 generateNumbers(),它会生成一个从 0 到 1000000 的数字序列。通过 yield 关键字,每次循环都会产生一个新的数字,并在迭代过程中输出到控制台。通过这种方式,我们可以逐步处理巨大的数据集,避免一次性加载整个数据集导致的性能问题。

3. 与其他语言特性的配合使用

        生成器函数在与其他 JavaScript 特性结合使用时,可以发挥更大的作用。

  • Iterator Protocol 迭代器协议 

        由于生成器函数返回的是一个可迭代对象,因此可以通过 for...of 循环来逐个访问生成的值。

function* shoppingList() {
    yield 'Milk';
    yield 'Eggs';
    yield 'Bread';
}

const myCart = shoppingList();

for (let item of myCart) {
    console.log(item);
}

  • 解构赋值 

        可以通过在生成器函数中使用解构赋值来获取生成的值的特定部分:

function* personDetails() {
    yield ["John", "Doe"];
    yield ["Jane", "Smith"];
}

const fullNameGenerator = personDetails();

for (let [firstName, lastName] of fullNameGenerator) {
    console.log(firstName, lastName);
}

  • 生成器和 Promise 的组合使用 

        生成器函数与异步编程结合使用,可以实现更灵活的控制流,简化异步操作的处理。下面我们分别介绍在生成器函数中如何使用 Promise 和 async/await 来处理异步编程。

        使用 Promise:
function fetchTodos() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(['Todo 1', 'Todo 2', 'Todo 3']);
    }, 2000);
  });
}

function* todoGenerator() {
  yield fetchTodos();
}

let generator = todoGenerator();
let promise = generator.next().value;

promise.then(todos => {
  console.log(todos);  // ['Todo 1', 'Todo 2', 'Todo 3']
});

        在上述代码中,我们定义了一个异步函数 fetchTodos(),它返回一个 Promise 对象,在 2 秒钟后会 resolve 一个包含待办事项的数组。然后,我们定义了一个生成器函数 todoGenerator(),其中通过 yield 关键字将 fetchTodos() 函数作为生成器的值进行暂停。

        在生成器对象上调用 next() 方法后,我们可以获取到 fetchTodos() 返回的 Promise 对象,然后可以使用 .then() 方法处理该 Promise 的结果。

        使用 async/await:
function fetchTodo() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Todo');
    }, 2000);
  });
}

function* todoGenerator() {
  try {
    let result = yield fetchTodo();
    console.log(result); // 'Todo'
    console.log('Generator continues...');

    // 可以在生成器函数中根据需要使用多个异步操作
    let anotherResult = yield someAsyncOperation();
    console.log(anotherResult);
    
    // ...
  } catch (error) {
    console.error(error);
  }
}

async function main() {
  const generator = todoGenerator();

  try {
    while (true) {
      const { value, done } = generator.next();
      
      if (done) {
        break;
      }

      await value;
    }
  } catch (error) {
    console.error(error);
  }
}

main();

        在上面的示例中:

  1. fetchTodo() 函数返回一个 Promise 对象,表示获取待办事项。生成器函数 todoGenerator() 使用 yield 暂停执行,并等待该 Promise 结果。

  2. main() 函数中,我们创建了一个迭代器对象 generator,通过循环并使用 await 关键字来依次执行生成器函数中的异步操作。

  3. 生成器函数中可以根据需要使用多个异步操作,使用 yield 暂停执行并等待每个操作完成。捕获可能的错误,可以使用 try-catch 块。

        PS. 生成器函数本身并不返回 Promise 对象,因此我们需要将生成器函数与 main() 函数结合使用,以确保异步操作按照预期顺序执行。

        总的来说,通过在生成器函数中结合 Promise、async/await 等异步编程特性,可以使生成器函数的控制流更加灵活、简洁和可读,从而提升异步编程的开发体验。

  • 委托给另外一个Generator函数

        委托(delegating)给另一个 Generator 函数是 Generator 函数在使用上的一种常见用法,它允许一个生成器函数调用另一个生成器函数,并将后者的生成器值逐个 yield 出来。这种委托机制可以简化代码结构,提高可读性,同时灵活地处理多个生成器之间的协作关系。

        示例代码:

function* generator1() {
  yield 1;
  yield 2;
}

function* generator2() {
  yield 'a';
  yield 'b';
}

function* combinedGenerator() {
  yield* generator1();  // 委托generator1()
  yield* generator2();  // 委托generator2()
  yield 'Final value';
}

let generator = combinedGenerator();

console.log(generator.next());  // { value: 1, done: false }
console.log(generator.next());  // { value: 2, done: false }
console.log(generator.next());  // { value: 'a', done: false }
console.log(generator.next());  // { value: 'b', done: false }
console.log(generator.next());  // { value: 'Final value', done: false }
console.log(generator.next());  // { value: undefined, done: true }

        在上述代码中,我们定义了三个生成器函数:generator1()generator2()combinedGenerator()。其中,combinedGenerator() 是我们将要创建的委托生成器函数。

        在 combinedGenerator() 中,通过使用 yield* 表达式,我们可以将执行权委托给其他生成器函数,即将 generator1()generator2() 的生成器值依次逐个 yield 出来。这样,在使用 combinedGenerator() 生成的生成器对象上调用 next() 方法时,它会检查当前生成器函数是否有委托的生成器函数可供调用。

        值得注意的是,通过委托给其他生成器函数,不仅可以在合并生成器值时保持代码的模块化和可复用性,还可以处理更复杂的生成器协作场景。在实际开发中,你还可以根据具体需求嵌套多个委托关系,以实现更灵活和高效的生成器编程。

        另外如果在委托生成器函数中发生异常(如:委托的生成器函数中出现错误、被主动生成器函数提前结束),该异常会被传递回主生成器函数并抛出。

        通过委托机制,JavaScript 中的 Generator 函数能够更好地组织和控制生成器之间的协作关系,使得代码更具可读性、可维护性,并且支持构建复杂的生成器流程。文章来源地址https://www.toymoban.com/news/detail-520892.html

到了这里,关于JavaScript 生成器函数详解:优雅处理异步任务流的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python中函数,装饰器,迭代器,生成器

    1.函数可以作为参数进行传递 2.函数可以作为返回值进行返回 3.函数名称可以当成变量一样进行赋值操作 作用:在不改变原有函数调用的情况下,给函数增加新的功能          即可以在函数前面增加新的功能,但不改变原来的代码 可迭代的数据类型都会提供迭代器,即可以

    2024年02月07日
    浏览(33)
  • Python生成器深度解析:构建强大的数据处理管道

    生成器是Python的一种核心特性,允许我们在请求新元素时再生成这些元素,而不是在开始时就生成所有元素。它在处理大规模数据集、实现节省内存的算法和构建复杂的迭代器模式等多种情况下都有着广泛的应用。在本篇文章中,我们将从理论和实践两方面来探索Python生成器

    2024年02月07日
    浏览(60)
  • 详解Python中的排列组合生成器

    在实际的开发场景中,经常需要遍历多个数组中的元素,将它们组合在一起使用。要取完所有可能的组合,最基本的方法是使用嵌套的循环,有多少个数组就嵌套多少层循环。嵌套循环是基本的原理,但不够简洁,Python中有更优雅的方式来实现这种功能。 在Python的内置模块

    2024年02月10日
    浏览(32)
  • ES6-2:Iterator、Proxy、Promise、生成器函数...

    打印出的是里面的内容,如果是for in打印出来的是索引,of不能遍历对象 Symbol.iterator是js内置的,可以访问直接对象arr[Symbol.iterator],()调用 对象非线性一般不能迭代 后两个是伪数组,但是是真迭代器接口 类似于数组,但成员的值都是唯一的,没有重复 与数组不同的是set没有

    2024年04月11日
    浏览(23)
  • 伪随机生成器(rand函数),随机数种子(srand函数)详细解读与分析:

    a.生成随机数; b.生成0~100以内的随机数 c.随机数的连续输出及其连续输出情况讲解与分析 首先我们来看一下rand函数(伪随机数生成器):   rand函数,即伪随机数生成器,该函数返回类型为整型,没有参数,即产生一个在(0-rand_max(十六进制的ox7ffff转化为整数即32767)的一个

    2024年02月11日
    浏览(37)
  • 【python基础语法六】迭代器,生成器,推导式和高阶函数

    内置函数: dir 获取当前对象的内置成员 高阶函数 : 能够把函数当成参数传递的就是高阶函数 (map ,filter ,reduce , sorted) 案例: 1. enumerate 2. zip 元组推导式是生成器( generator ) (1) 基本语法 (2) 优化生成器代码 (3) send 的使用方式 (给上一个 yield 发送数据) (4) yield from 的使用 (5) 案例

    2024年02月02日
    浏览(34)
  • 【沐风老师】3DMAX宇宙生成器(一键生成星系)插件使用方法详解

    3DMAX宇宙生成器(一键生成星系)插件  3DMAX宇宙生成器(一键生成星系)插件,用于模拟星团及星系的运动。可以创建单个集合进行动画计算,也可以输入不同坐标,建立多个集合后统一进行动画计算。 【安装方法】 无需安装,使用时直接拖动插件文件到3dMax视口打开即可

    2024年02月08日
    浏览(35)
  • 【html】利用生成器函数和video元素,取出指定时间的视频画面

    有的时候想截取视频某一秒的视频画面。 手动截取操作麻烦,还得时刻关注视频播放时间。 于是,我搞出来了一个根据视频自动截取特定时间描述的页面。 获取视频对象 根据视频时长生成时间选择表单 根据表单选择的时间和视频地址,利用canvas和vido元素生成某一帧的视频

    2024年02月07日
    浏览(25)
  • Faker库详解 - Python中的随机数据生成器

    Faker介绍 在软件测试过程中,我们经常需要使用一些测试数据,通常都是只能使用已有的系统数据,但可能会因权限或其它原因不可使用,又或者手工编造一些数据,但数据量较大时影响测试效率,Faker就解决这个问题,Faker是python的一个第三方库,主要是用来创造伪数据的,

    2024年02月05日
    浏览(34)
  • 实现高性能ID生成器:详解Java雪花算法

    Java中的雪花算法(Snowflake Algorithm)是一种用于生成唯一ID的算法,可以在分布式系统环境中防止ID重复。这种算法最初由Twitter开发,用于生成Twitter的唯一ID,由于其简单易懂和高效,已成为目前最常用的生成唯一ID的算法之一。 雪花算法生成的ID是一个64位的长整型数字,可

    2023年04月27日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包