async await 原理——generator 自执行

generator 函数自执行

redux-saga 中使用 generator 函数来进行流程控制。通常的 generator 函数在 yield 的地方中止后,需要使用 next 来继续执行,但是 saga 使用中我们并没有调用 next,说明 saga 已经在内部进行了处理,那么它是怎么处理的呢?

首先我们来看一个 generator 函数是怎样的:

function* gen() {
    yield 'a';
    yield 'b';
    return 'c';
}
const g = gen();
g.next();  // { value: a, done: false }
g.next();  // { value: b, done: false }
g.next();  // { value: c, done: true }

以上是一个基本的 generator 函数,我们需要使用 next 来执行。
那么如何让它自执行呢?

function next(g) {
    const { value, done } = g.next();
    if (!done) next(g);  // done 为 false,则递归调用 next
}
const g = gen();
next(g);

这样我们就能自执行上面那个简单的 generator 函数了。

但是,通常情况下,generator 函数中 yield 后面会是一个异步操作,通常是一个 promise 对象来进行,那么又是个什么情况呢?

// 首先声明一个异步调用方法,该方法返回一个 promise 对象
const asyncAdd = (num) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            num++;
            console.log('异步请求完成');
            resolve(num);
        }, 1000);
    });
};

function* add(num) {
    const res = yield asyncAdd(num);
    yield asyncAdd(res);
}

上面这个 generator 手动调用该怎么做呢?

const g = add(10);
// 调用 next 后获取到的 value,这时就是一个 promise 对象:{value: promise, done: false}
// 我们就需要调用 promise 的 then 方法来继续执行
g.next().value.then(num => g.next(num));

通过观察,我们就可以实现一个异步调用的自执行 generator 函数:

// 增加了一个 data 参数,作为 generator 内部 yield 的返回值
// 首次调用 next 的时候,值是在调用 generator 函数就传了,而不是在 .next 时传,所以 data 为 undefined 即可
function next(g, data) {
    // 通过调用 next 传入数据作为 generator 内部 yield 的返回值
    const { value, done } = g.next(data);
    // 按理来说需要判断 value 类型
    if (!done) value.then(res => next(g, res));
}
const g = add(10);  // 首次传参
next(g);

这样,就实现了带 promise 的 generator 自执行函数。

原文地址:https://www.cnblogs.com/3body/p/15476701.html