generator函数

本文详细介绍了JavaScript Generator函数的概念、语法、用法及其与普通函数的区别。通过具体代码示例,展示了如何创建、调用、控制Generator函数的执行流程,并讨论了Generator函数在异步编程中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Generator函数是ES6提供的一种异步编程解决方案

Generator暂停时,之后语句可以正常执行

之前异步编程的方法大概有四种

 1.回调函数

 2.事件监听

 3.发布/订阅

 4.Promise对象

从语法上理解,Generator函数是一个状态机,封装了多个内部状态,执行Generator函数会返回一个遍历器对象,也就是说Generator函数除了状态机还是一个遍历器对象生成函数。返回的遍历器对象,可以一次遍历Generator函数内部的每一个状态。

就像是在数组中取值,如果数组中有5个值,第一次只取一个值,则取值这个操作暂停,但是取值之后的主线程不会停止。

Generator函数是协程在ES6的实现,最大特点就是可以交出函数的执行权(即暂停执行)

整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方都用yield语句著名

function* helloWorldGenerator(){
    yield 'hello';
    yield 'world';
    return 'ending';
}
var hw=helloWorldGenerator();
console.log(hw.next());//{ value: 'hello', done: false }
console.log(hw.next());//{ value: 'world', done: false }
console.log(hw.next());//{ value: 'ending', done: true }
console.log(hw.next());//{ value: undefined, done: true }

定义Generator函数时使用function*  使用yield语句定义内部状态。以上代码有两个yield函数即有三个状态

调用函数后并不会执行,返回的是只想内部状态的指针对象也就是遍历器对象。

必须调用遍历器对象的next方法,使得指针移向下一个状态。每次调用next方法内部指针就从函数头部或上一次停下来的地方开始执行,知道遇到下一个yield语句(或return语句)为止。也就是说Generator函数是分段进行的,yield语句是暂停执行的标记,而next方法可以恢复执行
总结一下:调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后每次调用遍历对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束

yield语句

yield语句和return 语句相似处:返回紧跟在语句后面的那个表达式的值。区别处:遇到yield语句函数暂停,下次从该位置执行,而return 语句不具备记忆功能,且return 语句只能运行一次。

在普通函数中添加yield语句会报错

在Generator函数总可以不使用yield,那么该Generator就变为了一个单纯的暂缓执行函数

function* f(){
    console.log('执行');
}
var generator=f();
setTimeout(function(){
    generator.next();
},2000)
next方法的参数

yield语句本身没有返回值,总是返回undefined。next方法可以带一个函数,该函数会被当作上一个yield语句的返回值,第一个next方法带参数无效,方法是用来启动遍历器对象。

function* helloWorldGenerator(){
    var step1= yield 'hello';
    console.log(step1);//step1
    var step2= yield 'world';
    console.log(step2);//undefined
    return 'ending';

}
var hw=helloWorldGenerator();
console.log(hw.next());//{ value: 'hello', done: false }
console.log(hw.next('step1'));//{ value: 'world', done: false }
console.log(hw.next());//{ value: 'ending', done: true }
console.log(hw.next());//{ value: undefined, done: true }
Generator函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过next方法的参数,在Generator函数开始运行之后,继续向函数内部注入值。可以在Generator函数运行的不同阶段,从外部想内部注入不同的值,从而调整函数行为。

for...of循环

for...of循环可以自动遍历Generator函数,且不再需要调用next方法

function* foo(){
    yield 1;
    yield 2;
    yield 3;
    yield 4;
    yield 5;
    return 6;
}
for(var v of foo()){
    console.log(v);
}
//1 2 3 4 5
使用for...of循环,此次显示了5个yield语句的值。一旦next方法的返回对象的done属性为true,循环就会终止,且不包含该返回对象,及不包含代码中return语句返回值

Generator.prototype.throw()

Generator函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后再Generator函数体内捕获

var  g=function* (){
    while(true){
        try{
            console.log('运行');
            yield 1;
        }catch(e){
            if(e != 'a') throw  e;
            console.log('内部捕获',e);
        }
    }
};
var i= g();
i.next();
console.log('异常测试');
try{
    i.throw('a');
    i.throw('b');
    i.throw('c');
}catch(e){
    console.log('外部捕获',e);
}
//运行
//异常测试
//内部捕获 a
//运行
//外部捕获 b
如果Generator函数内部部署了try...catch代码块,那么遍历器的throw方法抛出的错误,不影响下一次遍历,否则遍历直接终止

function* g(){
    try {
        var a = yield foo('a');
        var b = yield foo('b');
        var c = yield foo('c');
    } catch (e) {
        console.log(e);
    }

    console.log(a, b, c);
}
函数异常判断

yield* 语句

yield* 语句表明它返回的是一个遍历器对象

function* foo(){
    yield 2;
    yield  3;
    yield  4;
    return "foo";
}
function* bar(){
    yield 1;
    yield *foo();
    yield 5;
}
var it=bar();
console.log(it.next());//{ value: 1, done: false }
console.log(it.next());//{ value: 2, done: false }
console.log(it.next());//{ value: 3, done: false }
console.log(it.next());//{ value: 4, done: false }
console.log(it.next());//{ value: 5, done: false }
console.log(it.next());//{ value: undefined, done: true }

### 什么是 Generator 函数 Generator 函数是 ES6 中引入的一种特殊类型的函数,它可以返回一个迭代器对象。通过该迭代器对象,可以逐步执行 Generator 函数中的代码并获取其内部的值[^4]。 #### 基本语法 定义一个 Generator 函数时,在 `function` 关键字后面加上星号 (`*`) 表示这是一个 Generator 函数。在函数体中使用 `yield` 关键字暂停和恢复函数的执行,并返回相应的值[^3]。 ```javascript function* myGenerator() { yield 1; yield 2; yield 3; } const generator = myGenerator(); console.log(generator.next().value); // 输出 1 console.log(generator.next().value); // 输出 2 console.log(generator.next().value); // 输出 3 ``` 上述代码展示了如何创建一个简单的 Generator 函数以及如何通过 `.next()` 方法逐步获取生成器返回的值。 --- ### Generator 的工作原理 当调用一个 Generator 函数时,实际上并不会立即执行其中的代码,而是返回一个迭代器对象。每次调用迭代器的 `.next()` 方法时,都会从上一次停止的地方继续执行直到遇到下一个 `yield` 或者到达函数结束位置。 如果 Generator 函数中有多个 `yield` 表达式,则可以通过多次调用 `.next()` 来逐一处理这些表达式的值。 --- ### 复杂场景下的 Generator 使用 #### 调用嵌套的 Generator 函数 默认情况下,直接在一个 Generator 函数中调用另一个 Generator 函数不会自动展开后者的结果。为了实现这一点,需要显式地使用 `yield*` 将子生成器的内容合并到父生成器中[^5]。 ```javascript function* foo() { yield 'aaa'; yield 'bbb'; } function* bar() { yield* foo(); // 展开foo生成器的内容 yield 'ccc'; yield 'ddd'; } let iterator = bar(); for (let value of iterator) { console.log(value); } // aaa bbb ccc ddd ``` 在这里可以看到,`yield*` 提供了一种简洁的方式来组合不同层次的生成逻辑。 --- ### 实现异步操作的同步化表达 利用 Generator 函数配合协程模式(coroutine),能够简化复杂的异步流程管理问题。通常结合第三方库如 co.js 或原生的 async/await 功能来完成这一目标[^1]。 下面是一个基于手动驱动的方式模拟异步请求的例子: ```javascript function wait(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function* taskScheduler() { console.log('Task started'); yield wait(1000); // 模拟耗时任务 console.log('After first delay'); yield wait(2000); // 又一段延迟 console.log('All tasks completed'); } const schedulerIterator = taskScheduler(); (function exec() { const result = schedulerIterator.next(); if (!result.done) { result.value.then(() => exec()); } })(); ``` 此例子说明了即使面对多阶段延时计算的情况,借助于 Generators 和 Promises 结合也可以让程序看起来像顺序执行那样直观易懂[^1]。 --- ### 总结 - **基本功能**:提供一种机制允许开发者分段运行 JavaScript 程序片段。 - **核心概念**:依靠 `yield/yield*` 控制权转移;依赖 `.next()` 推动进程向前发展。 - **实际用途**:除了作为普通的迭代工具外,还特别适合用来解决复杂状态转换或者协调长时间等待的任务链路等问题。 --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值