我已经使用JavaScript生成器such as this one阅读了几个代码示例。我能提出的最简单的生成器使用块是:
function read(path) {
return function (done) {
fs.readFile(path, "file", done);
}
}
co(function *() {
console.log( yield read("file") );
})();
这确实打印出file
的内容,但我的挂断是调用done
的地方。看起来,yield是用于包装它在回调中返回的内容并适当地分配结果值的语法糖(至少在co
的情况下,将错误参数抛给回调)。我对语法的理解是否正确?
使用done
时yield
看起来像什么?
答案 0 :(得分:3)
看起来,yield是一个语法糖,用于包装它在回调中返回的内容并适当地分配结果值(至少在co的情况下,将错误参数抛给回调)
不,yield
不是语法糖。它是生成器的核心语法元素。实例化该生成器后,您可以运行它(通过调用它上面的.next()
),这将返回return
ed或yield
ed的值。当生成器yield
时,您可以稍后再次调用.next()
继续它。 next
的参数将是yield
表达式在生成器内返回的值。
co
的情况下仅,处理这些异步回调事物(和other things)"恰当"对于你在异步控制流程库中认为自然的东西。
使用产量时的效果如何?
article that you read中的thread
功能示例给您留下了很好的印象:
function thread(fn) {
var gen = fn();
function next(err, res) {
var ret = gen.next(res);
if (ret.done) return;
ret.value(next);
}
next();
}
在您的代码中,yield
确实在运行时从生成器中生成表达式read("file")
的值。这变为ret.val
,gen.next()
的结果。为此,传递了next
函数 - 一个回调函数,它将继续生成具有传递给它的res
ult的生成器。在您的生成器代码中,看起来好像yield
表达式返回了此值。
"展开"发生的事情的版本可以这样写:
function fn*() {
console.log( yield function (done) {
fs.readFile("filepath", "file", done);
} );
}
var gen = fn();
var ret1 = gen.next();
var callasync = ret1.value;
callasync(function next(err, res) {
var ret2 = gen.next(res); // this now does log the value
ret2.done; // true now
});
答案 1 :(得分:2)
我发布了有关生成器如何工作here的详细说明。
以简化形式,您的代码可能看起来没有co
(未经测试):
function workAsync(fileName)
{
// async logic
var worker = (function* () {
function read(path) {
return function (done) {
fs.readFile(path, "file", done);
}
}
console.log(yield read(fileName));
})();
// driver
function nextStep(err, result) {
try {
var item = err?
worker.throw(err):
worker.next(result);
if (item.done)
return;
item.value(nextStep);
}
catch(ex) {
console.log(ex.message);
return;
}
}
// first step
nextStep();
}
workAsync("file");
workAsync
的驱动程序部分通过调用nextStep()
异步迭代生成器对象。