避免在类似协程的 JavaScript 函数中重复 "yield"

Avoiding "yield" repetition in coroutine-like JavaScript function

我正在使用 io.js,一个已经支持 ES6 生成器而无需特殊标志的节点分支,以及 Kris Kowal 的 Q 库。

我正在制作的是一个游戏脚本,其中几乎每个动作都是异步的,我正在使用 Q.spawn 来保持理智。这是我的代码的当前状态,它有效:

var q = require('q');
var tw = require('./lib/typewriter');
q.spawn(function*() {
    tw.clear();
    yield tw.type({d:100}, "August 3, 9:47 AM", {w:500});
    yield tw.type("District Court");
    yield tw.type("Defendant Lobby No. 2", {w:2000});
    yield tw.breakLine();
    yield tw.type({who:"Phoenix"}, {dh:true}, {d:30}, "(Boy am I nervous!)", {w:1500});
    yield tw.breakLine().then(function(){ throw new Error("BOOM!"); });
    yield tw.type({who:"Mia"}, {dh:true}, {d:40}, "Wright!", {w:1250});
    yield tw.type({di:true}, {d:50}, "Did you", {w:1000}, {d:0}, " ", {d:30}, "turn off the lights?", {w:1000});
    yield tw.type({di:true}, {d:400}, ". . .", {w:1000});
    yield tw.type({di:true}, {d:40}, "I can't see a thing!", {w:1000});
    yield tw.breakLine();
    process.exit();
});

但是,为每一行添加产量很糟糕。我几乎要跳到 Luvit 以摆脱这种疯狂,但我正在给 JavaScript 机会。

一般情况下,我可以省略大部分yield,像这样:

var q = require('q');
var tw = require('./lib/typewriter');
q.spawn(function*() {
    tw.clear();
    tw.type({d:100}, "August 3, 9:47 AM", {w:500});
    tw.type("District Court");
    tw.type("Defendant Lobby No. 2", {w:2000});
    tw.breakLine();
    tw.type({who:"Phoenix"}, {dh:true}, {d:30}, "(Boy am I nervous!)", {w:1500});
    tw.breakLine();
    tw.type({who:"Mia"}, {dh:true}, {d:40}, "Wright!", {w:1250});
    tw.type({di:true}, {d:50}, "Did you", {w:1000}, {d:0}, " ", {d:30}, "turn off the lights?", {w:1000});
    tw.type({di:true}, {d:400}, ". . .", {w:1000});
    tw.type({di:true}, {d:40}, "I can't see a thing!", {w:1000});
    yield tw.breakLine();
    process.exit();
});

只有一个 yield 仍然存在,只是为了确保 process.exit() 不会执行得太早。打字机模块实际上对大多数命令进行了排队,所以这是可行的。这应该是合理的。

但是,如果回调在某处抛出,如:

tw.breakLine().then(function(){ throw new Error("BOOM!"); });

然后 Q 将吞下它,并且由于没有 catch 处理程序附加到该承诺,它将被静默地垃圾收集。

如果 JavaScript 生成器刚刚检测到表达式语句产生 promise 并自动产生它,那将是 awesome(只要你能以某种方式选择退出它,当然)。

是否有 JavaScript 预处理器可以做到这一点?

或者是否有其他方法可以避免在每一行上显式让步,但仍然会捕获异常?

If JavaScript generators just detected expression statements yielding promises and automatically yielded that, it would be awesome.

It would be terrible.

Or is there some other way to avoid explicitly yielding on every single line but still get exceptions to be caught?

不是真的。但是对于您的用例,我建议使用异步辅助函数来减少要使用的 yield 的数量:

var paragraph = q.async(function*(lines) {
    for (let line of lines)
        yield tw.type(...line);
    yield tw.breakLine();
});
q.spawn(function*() {
    tw.clear();
    yield paragraph([
        [{d:100}, "August 3, 9:47 AM", {w:500}],
        ["District Court"],
        ["Defendant Lobby No. 2", {w:2000}]
    ]);
    yield paragraph([
        [{who:"Phoenix"}, {dh:true}, {d:30}, "(Boy am I nervous!)", {w:1500}]
    ]);
    throw new Error("BOOM!");
    yield paragraph([
        [{who:"Mia"}, {dh:true}, {d:40}, "Wright!", {w:1250}],
        [{di:true}, {d:50}, "Did you", {w:1000}, {d:0}, " ", {d:30}, "turn off the lights?", {w:1000}],
        [{di:true}, {d:400}, ". . .", {w:1000}],
        [{di:true}, {d:40}, "I can't see a thing!", {w:1000}]
    ]);
    process.exit();
});