JavaScript的生成器与组合学习

基本介绍

生成器是 JavaScript 中的一种特殊函数,能够在执行过程中暂停,并且在需要的时候恢复执行。这与普通函数的执行方式不同,普通函数一旦开始执行,必须执行完所有语句后才会返回,而生成器可以在执行过程中多次暂停。

1. 基本语法

生成器函数由 function* 定义,内部使用 yield 关键字来暂停执行。每次调用生成器函数时,它不会立即执行代码,而是返回一个生成器对象(Generator 对象)。通过调用这个对象的 next() 方法,才会逐步执行代码,直到遇到 yield 关键字。

//myGenerator 函数是一个生成器函数,它在执行过程中依次 yield 出 1、2、3。
//每次 yield 表示函数暂停,等待下一次 next() 调用来继续执行。
function* myGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

const gen = myGenerator();

console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
//next() 方法:
//value: 生成器 yield 出的值。
//done: 当生成器遍历完成时为 true,否则为 false。
//生成器的执行流程可以通过 next() 方法逐步推进,函数执行到 yield 时暂停,
//等到下次调用 next() 时继续执行。

生成器与迭代器(Iterators)的关系

迭代器是 JavaScript 中一种用于遍历数据集合(如数组、字符串)的对象,它有一个 next() 方法,每次调用 next() 会返回集合中的下一个值。生成器实际上是一个实现了迭代器协议的对象,它天生就是迭代器!

1. 迭代器的原理

迭代器对象需要具有一个 next() 方法,next() 方法返回一个对象,包含:

value: 当前的值。
done: 一个布尔值,指示迭代是否完成。
手动创建迭代器的例子:

function createIterator(arr) {
    let index = 0;
    return {
        next: function() {
            if (index < arr.length) {
                return { value: arr[index++], done: false };
            } else {
                return { value: undefined, done: true };
            }
        }
    };
}

const iterator = createIterator([1, 2, 3]);

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

生成器作为迭代器

生成器函数自动实现了迭代器协议,不需要手动编写 next() 方法。生成器非常方便地创建可迭代对象。

使用生成器代替手动迭代器:

function* createGenerator(arr) {
    for (let i = 0; i < arr.length; i++) {
        yield arr[i];
    }
}

const gen = createGenerator([1, 2, 3]);

console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
//实际上,所有的生成器都是迭代器!

生成器与 Promise 结合

生成器的暂停和恢复机制使得它可以与 Promise 结合起来,处理异步代码。这种模式被称为“协程”(coroutine),它使得异步代码看起来更像同步代码。

1. 使用生成器处理异步操作

假设我们有一个 Promise 返回的异步函数:

function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => resolve("数据加载完成"), 1000);
    });
}

//通常我们会通过 .then() 或者 async/await 来处理这个 Promise。
//然而,生成器也可以用来处理异步操作,配合 next() 和 yield 来暂停和恢复执行

function* asyncGenerator() {
    console.log("开始加载数据...");
    const data = yield fetchData(); // 暂停,等待数据加载完成
    console.log(data); // 数据加载完成
}

//生成器的 yield 可以等待 Promise 的结果返回。
//在 yield 后,生成器暂停,直到我们手动恢复执行。
手动执行生成器处理 Promise

要执行上面的生成器并让它处理异步操作,我们可以手动编写控制逻辑:

const gen = asyncGenerator();

const result = gen.next(); // 开始加载数据...

result.value.then((data) => {
    gen.next(data); // 恢复生成器的执行,传入异步操作结果
});

//通过调用 gen.next(),生成器暂停在 yield 处,等待异步操作完成。
//异步操作完成后,通过 gen.next(data) 继续执行,并把数据传递回生成器。
自动执行生成器与 Promise 的结合

为了简化手动调用生成器,我们可以编写一个自动执行生成器的函数:

function runGenerator(genFunc) {
    const gen = genFunc();

    function handleNext(nextValue) {
        const result = gen.next(nextValue);

        if (!result.done) {
            result.value.then(handleNext); // 等待 Promise 完成,再继续执行
        }
    }

    handleNext(); // 启动生成器
}

runGenerator(asyncGenerator);

//这个 runGenerator 函数能够自动执行生成器中的异步操作,无需手动调用 next(),类似于 //async/await 的效果

生成器与 async/await

生成器与 async/await 非常相似,都是用来处理异步代码的工具。async/await 其实是生成器的更高级抽象,专门用于处理 Promise。async 函数内部使用的是生成器的思想,只不过 JavaScript 通过引擎帮我们自动管理了 next() 的调用。

对比:

生成器:需要手动调用 next() 处理异步逻辑。
async/await:是生成器的封装,自动处理 next() 的调用,代码更简洁。
生成器版本

function* asyncGenerator() {
    const data = yield fetchData();
    console.log(data);
}

async/await版

async function asyncFunction() {
    const data = await fetchData();
    console.log(data);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值