如何从 JavaScript 中的递归生成器函数返回?

ccn*_*kes 5 javascript recursion ecmascript-6

我正在玩一个递归生成器函数,它异步返回值。我正在使用协程包装函数来调用它。代码和JSBin如下:

http://jsbin.com/nuyovay/edit?js,控制台

let log = console.log.bind(console);
let err = console.error.bind(console);

function coroutine(generatorFn){
    return function co() {
        let generator = generatorFn.apply(this, arguments);

        function handle(result) {
            console.log(result);
            if (result.done) {
                return Promise.resolve(result.value);
            }
            return Promise.resolve(result.value)
                .then(
                    res => handle(generator.next(res)),
                    err => handle(generator.throw(err))
                );
        }

        try {
            return handle(generator.next());
        } catch (err) {
            return Promise.reject(err);
        }
    };
}

function sleep(dur) {
    return new Promise(res => {
        setTimeout(() => { res() }, dur);
    });
}

function* recurse(limit = 5, count = 0) {   
    if(count < limit) {
        yield sleep(100).then(() => Promise.resolve(++count));
        yield* recurse(limit, count);
    }
    else {
        return count;
    }
}

let test = coroutine(recurse);

test().then(log).catch(err);
Run Code Online (Sandbox Code Playgroud)

运行此返回:

Object {value: Promise, done: false}
Object {value: Promise, done: false}
Object {value: Promise, done: false}
Object {value: Promise, done: false}
Object {value: Promise, done: false}
// `value` should be 5
Object {value: undefined, done: true}
Run Code Online (Sandbox Code Playgroud)

return生成器的 final是怎么来的undefined?当我将上述内容用于 bluebird's 时Promise.coroutine,我得到了相同的结果。我是否遗漏了递归生成器的一些基本知识?我如何得到它{ value: 5, done: true }

nil*_*ils 4

问题是您正在返回count,但您正在父生成器中返回它。yield与委托生成器不同,return它不会通过委托链自动生成备份。

如果你想获取return委托生成器的值,你必须直接在父生成器中分配它:

let returnValue = yield* recurse(limit, count);
Run Code Online (Sandbox Code Playgroud)

由于您使用的是“递归”生成器(多个委托级别),因此您需要重复该过程并返回每个委托级别的值:

function* recurse(limit = 5, count = 0) {   
    if(count < limit) {
        yield sleep(100).then(() => Promise.resolve(++count));
        let result = yield* recurse(limit, count); // save the return value
        return result; // return it to the parent
    }
    else {
        return count;
    }
}
Run Code Online (Sandbox Code Playgroud)