【问题标题】:Avoiding "yield" repetition in coroutine-like JavaScript function在类似协程的 JavaScript 函数中避免“yield”重复
【发布时间】:2015-06-28 08:08:23
【问题描述】:

我正在使用 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 机会。

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

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 的表达式语句并自动产生它,那将是真棒(当然,只要你能以某种方式选择退出它)。

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

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

【问题讨论】:

  • 你为什么会有“一个在某处抛出的回调”?如果您使用回调,为什么不屈服?还是 tw 本身失败了?
  • 很多事情都可能导致异常被抛出,例如一个错误,一个未定义的属性被作为函数调用会抛出一个 TypeError。我只是不希望这些事情不被报道,基本上,它们几乎可以在任何地方发生。
  • 是的,但是如果错误出现在tw 库中,那么您基本上会措手不及,并且无能为力。如果存在内部队列,则库有责任拒绝返回的承诺,以及依赖于它的承诺。
  • 它们要么传播到Q.spawn(),要么传播到从拒绝链中调用它的promise。如果它传播到Q.spawn(),很好,它会抛出。在后一种情况下,它就像解析链中的任何其他错误一样(它会被吞没)。所以我认为它会是一样的......

标签: javascript node.js yield q io.js


【解决方案1】:

如果 JavaScript 生成器只是检测到产生 Promise 的表达式语句并自动产生它,那就太棒了。

It would be terrible.

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

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

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();
});

【讨论】:

  • 我不知道。我同意同步控制流保证很重要,通常是人们想要的,但我认为自动屈服可能很有趣,如果只是作为一个实验。如果我知道如何制作不会在错误报告中弄乱行/列偏移的预处理器,我真的很想尝试一下。
  • 还有一点让我很困扰:如果我不小心忘记了让步,我的代码可以运行,但是异常会被 Q 吞没。因为这是一个游戏,而这个库并不能真正产生可恢复的错误,我会让tw 附加一个导致异常泄漏的处理程序。如果它们发生了,整个游戏就会崩溃,但这总比默默地忽略它们要好......
  • 嗯,这行不通。 Q.done() 就是这样做的,但我不能确保客户端代码(tw 之外)会根据自己的承诺使用 .done()。所以我仍然必须记住每次都调用它,或者让步。我真的希望社区能找到一种方法让这更安全...... :(
  • 好吧,高级承诺库使用未处理的拒绝跟踪。 Afaik Q 支持吗?
  • 我没有意识到这一点。我确实认为Q有它。但是,我必须选择一个我说“好的,如果此时仍有未处理的错误,请抛出它们”的地方。我仍然必须明确地这样做,但我想这是有道理的。谢谢!
猜你喜欢
  • 2021-07-08
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多