【问题标题】:How can I emulate a synchronous call with generators in javascript?如何在 javascript 中使用生成器模拟同步调用?
【发布时间】:2015-05-31 19:38:39
【问题描述】:

假设下一段代码:

var co = require('co');

var myObj = {
    getFieldValue: function() {
        var self = this;
        console.log(JSON.stringify(self));
        if (!self.fieldValue) {
            return function(cb) {
                // Emulate an async database load
                setTimeout(function() {
                    self.fieldValue = "the value from the database\n";
                    cb(null, self.fiedValue);
                }, 5000);
            };
        } else {
             return function(cb) {
                cb(null, self.fieldValue);
            };
        }
    },
};

co(function *() {
    var v1 = yield myObj.getFieldValue();
    console.log(v1);
    var v2 = yield myObj.getFieldValue();
    console.log(v2);
});

如您所见,我使用单个方法 getFieldValue 定义 myObj。第一次调用此方法时,它会从数据库中加载值。该值被缓存,并在后续调用中直接返回该值。该解决方案效果很好,但是对象的用户必须在生成器上下文中运行,并在每次访问对象方法之前编写一个 yield。

我可以假设所有调用都将在生成器上下文中完成。但是有没有办法重写 myObj 实现,让用户不需要包含 yield 关键字?

我希望用户可以写一些这样的东西(没有收益):

co(function *() {
    var v1 = myObj.getFieldValue();
    console.log(v1);
    var v2 = myObj.getFieldValue();
    console.log(v2);
});

【问题讨论】:

  • 使用 ES6 迭代器协议实现 next() 方法是否可以解决问题,例如 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 为什么要避开yields?它们是生成器的关键元素,并允许异步恢复?
  • @Bergi 因为它是“脏的”。我想使用与 myObj 相同的 api,而不关心它是同步实现还是异步实现。 var myObj = { getFieldValue: function() { return this.fieldValue; } }
  • 仅供参考。 esdiscuss.org/topic/does-async-await-solve-a-real-problem 对此有很大的讨论
  • @jbaylina:对我来说,隐含阻塞似乎很荒谬。但是让我们在 github 上讨论这个问题(或者如果你已经在 esdiscuss 那里发布了它)。

标签: javascript generator ecmascript-6 co


【解决方案1】:

如果有帮助,我最近使用 C 语言为 UNIX 编写的 rogue 的第一个版本,并重写了它以使 javascript 在浏览器中工作。我使用了一种称为 continuation 的技术来等待用户输入密钥,因为在 javascript 中没有中断。

所以我会有一段这样的 C 代码:

void function f() {

  // ... first part

  ch = getchar();

  // ... second part

}

将被转化为

function f(f_higher_cont) {

  // ... first part

  var ch = getchar(f_cont1);

  return;
  // the execution stops here 

  function f_cont1 () {

    // ... second part
    f_higher_cont();
  }
}

然后存储延续以在按键事件上重复使用。随着关闭,一切都将在它停止的地方重新启动。

【讨论】:

  • 这是在 javascript 中进行常规异步调用的方式。我要问的是另一回事。无论如何,非常感谢您的回答。
猜你喜欢
  • 2017-05-12
  • 2016-07-10
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 2016-08-21
  • 1970-01-01
  • 2018-05-02
  • 1970-01-01
相关资源
最近更新 更多