我正在玩一个递归生成器函数,它以异步方式返回值。我正在使用协程包装函数来调用它。代码和JSBin如下:
http://jsbin.com/nuyovay/edit?js,console
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);
运行此命令返回:
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}
生成器的最终return
怎么来undefined
?当我将上述内容用于bluebird的Promise.coroutine
时,我会得到相同的结果。我错过了关于递归生成器的基本内容吗?如何将其转到{ value: 5, done: true }
?
答案 0 :(得分:4)
问题是您要返回count
,但是您要在父生成器中返回它。与委派生成器中的yield
不同,return
不会通过委派链自动备份。
如果要获取委派生成器的return
值,则必须直接在父生成器中分配它:
let returnValue = yield* recurse(limit, count);
因为您正在使用&#34;递归&#34;生成器(多级授权),您需要重复该过程并在每个授权级别返回值:
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;
}
}
答案 1 :(得分:2)
在if
中,您的一边只有return
。
您也不需要在发电机内使用.then
。使用生成器的全部意义在于,您无需触及其中的promise API。
相反,请使用recurse
count + 1
function* recurse(limit = 5, count = 0) {
if(count < limit) {
yield sleep(1000).then(() => Promise.resolve(++count));
return yield* recurse(limit, count + 1);
}
else {
return count;
}
}
因为您正在使用ES6,而我们正在使用它......
return function co() {
let generator = generatorFn.apply(this, arguments);
......最好...... ...
return function co(...args) {
let generator = generatorFn(...args)
现在一起
运行代码段,您将在此处看到正确的输出
let log = console.log.bind(console);
let err = console.error.bind(console);
function coroutine(generatorFn){
return function co(...args) {
let generator = generatorFn(...args)
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)
return yield* recurse(limit, count + 1);
}
else {
return count;
}
}
let test = coroutine(recurse);
test().then(log).catch(err);
&#13;
答案 2 :(得分:1)
对于那些想知道的人:这不是coroutine
助手的用法。函数本身应该通过包装版本递归,如下所示:
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);
});
}
const recurse = coroutine(function* (
limit = 5, count = 0
) {
if(count < limit) {
yield sleep(100);
++count;
return yield recurse(limit, count);
} else {
return count;
}
});
recurse().then(log).catch(err);
&#13;
异步函数定义为常规函数,返回Promise
,永不抛出同步异常。 coroutine
帮助程序只是帮助您编写异步函数。如果您熟悉其他语言的async / await,则此包装器旨在将生成器转换为异步函数,其中所有await
都由yield
替换。考虑到这一点,这些函数更容易推理,因此人们不必争论生成器,只需要异步函数。