0

0

JS如何实现生成器协程?协程的调度

月夜之吻

月夜之吻

发布时间:2025-08-21 13:46:01

|

1017人浏览过

|

来源于php中文网

原创

JavaScript通过生成器函数function*和yield实现协程,调用生成器函数返回生成器对象,执行时遇到yield暂停并返回值,通过next()方法恢复执行且可传参,实现双向通信;生成器保持内部状态,支持惰性求值和分步执行,常用于异步流程控制;为调度生成器协程,需编写执行器函数run,其递归调用next()并处理yield出的Promise,实现类似async/await的异步串行化执行,从而完成合作式多任务调度。

js如何实现生成器协程?协程的调度

JavaScript 中的生成器(Generator)提供了一种非常巧妙的方式来实现协程(Coroutine)。简单来说,它允许函数在执行过程中暂停,然后根据外部指令在之后恢复执行,甚至可以双向传递数据。这种“暂停-恢复”的能力,正是构建协程的核心。至于调度,通常需要一个外部的“执行器”或“调度器”来管理生成器的推进,特别是在处理异步操作时,它会负责在正确时机调用生成器的

next()
方法。

要理解JS如何实现生成器协程,我们得从

function*
这个语法糖说起。它定义了一个生成器函数,执行它并不会立即运行函数体,而是返回一个生成器对象(Generator Object),这个对象遵循迭代器协议。

关键在于

yield
关键字。当生成器函数执行到
yield
表达式时,它会暂停执行,并将
yield
后面的值作为
next()
方法的结果返回。函数的状态会被保存下来,等待下一次
next()
调用。

看个简单的例子:

function* myCoroutine() {
    console.log('协程开始');
    let x = yield '第一次暂停,请给我一个值';
    console.log('协程恢复,得到了值:', x);
    let y = yield '第二次暂停,再给我一个值';
    console.log('协程再次恢复,得到了值:', y);
    return '协程结束';
}

const co = myCoroutine();

console.log(co.next().value); // 输出:协程开始 \n 第一次暂停,请给我一个值
console.log(co.next('Hello').value); // 输出:协程恢复,得到了值: Hello \n 第二次暂停,再给我一个值
console.log(co.next('World').value); // 输出:协程再次恢复,得到了值: World \n 协程结束

在这个例子里,

myCoroutine
就是一个简单的协程。它通过
yield
将控制权交出去,又通过
next()
被外部唤醒。
next()
方法还可以接收参数,这个参数会成为上一个
yield
表达式的返回值,实现了协程与外部的双向通信。这就是协程最基础的形态:合作式多任务,函数自己决定何时暂停,何时交出控制权。

生成器函数与普通函数有何本质区别?它们如何实现执行流的“暂停”与“恢复”?

我觉得,理解生成器和普通函数最大的不同,就像理解电影和照片的区别。普通函数就像一张照片,一旦拍下(执行),就定格了,从头到尾一次性完成。而生成器函数则像一部电影,你可以在任何一个“暂停”点(

yield
)停下来,观察当前画面,甚至给它一些指令,然后它再继续播放。

具体来说,普通函数被调用后,会一直执行直到遇到

return
语句或函数体结束。它的局部变量和执行状态在每次调用后都会被销毁。

Android传感器编程 中文WORD版
Android传感器编程 中文WORD版

本文档主要讲述的是Android传感器编程;传感器是一种物理装置或生物器官,能够探测、感受外界的信号、物理条件(如光、热、湿度)或化学组成(如烟雾),并将探知的信息传递给其它装置或器官。同时也可以说传感器是一种检测装置,能感受被测量的信息,并能将检测的感受到的信息,按一定规律变换成为电信号或其它所需形式的信息输出,以满足信息的传输、处理、存储、显示、记录和控制等要求。它是实现自动检测和自动控制的首要环节。感兴趣的朋友可以过来看看

下载

生成器函数则不同。

  1. *`function` 语法:** 这是它最明显的标志。
  2. 惰性执行: 调用生成器函数不会立即执行其内部代码,而是返回一个“生成器对象”(Generator Object)。这个对象本身就是一个迭代器(Iterator)和可迭代对象(Iterable)。
  3. yield
    关键字:
    这是实现暂停和恢复的魔法。当生成器执行到
    yield
    表达式时,它会暂停当前函数的执行,将
    yield
    后面的值“产出”(yield)给外部,并将当前的执行上下文(包括局部变量、程序计数器等)完整地保存下来。
  4. next()
    方法:
    外部通过调用生成器对象的
    next()
    方法来“推动”生成器继续执行。每次调用
    next()
    ,生成器都会从上次
    yield
    暂停的地方恢复执行,直到遇到下一个
    yield
    return
    next()
    方法返回一个对象
    { value: any, done: boolean }
    value
    yield
    return
    的值,
    done
    表示生成器是否已执行完毕。
  5. 状态保持: 这是最关键的一点。生成器能够“记住”它上次暂停时的所有状态,所以当它恢复时,就像从未离开过一样。

这种独特的行为模式,让生成器非常适合处理需要分步执行、或者需要外部控制流程的场景,协程只是其中一个非常典型的应用。

JavaScript中,我们通常如何调度生成器协程,以实现复杂的异步流程控制?

协程的魅力在于“调度”,也就是如何管理这些可暂停的执行流。在JavaScript中,由于它是单线程的,我们说的“调度”并非操作系统层面的时间片轮转,而是一种“合作式调度”:生成器自己决定何时暂停,并将控制权交还给调度器。调度器则负责在合适的时候,比如一个异步操作完成后,再次唤醒生成器。

最常见的调度模式就是编写一个“执行器”(Runner)或“调度器”(Scheduler)函数。这个函数会接收一个生成器对象作为输入,然后通过递归或循环的方式,不断调用生成器的

next()
方法,直到生成器执行完毕。

当生成器

yield
出一个值时,调度器需要判断这个值的类型。如果它是一个Promise,那么调度器就会等待这个Promise解析(resolved)后,再将解析结果作为参数传给生成器的下一个
next()
调用。这正是
async/await
底层逻辑的简化版。

我们来构建一个简单的异步协程调度器:

function run(generatorFunc) {
    const generator = generatorFunc(); // 获取生成器实例

    function step(nextData) {
        const result = generator.next(nextData); // 推进生成器

        if (result.done) {
            return Promise.resolve(result.value); // 生成器完成,返回最终值
        }

        // 如果yield出来的是一个Promise,就等待它
        return Promise.resolve(result.value)
            .then(data => step(data)) // Promise成功,将结果传回生成器继续执行
            .catch(error => generator.throw(error)); // Promise失败,将错误抛回生成器
    }

    return step(); // 启动调度
}

// 示例:一个包含异步操作的生成器协程
function* asyncTask() {
    console.log('开始异步任务

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

351

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

32

2025.11.30

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

525

2023.08.10

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

515

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

245

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

340

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5331

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

483

2023.09.01

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

33

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Rust 教程
Rust 教程

共28课时 | 5.1万人学习

PostgreSQL 教程
PostgreSQL 教程

共48课时 | 8.2万人学习

Git 教程
Git 教程

共21课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号