【问题标题】:How can I handle a callback synchrnously in Node.js?如何在 Node.js 中同步处理回调?
【发布时间】:2012-05-14 19:35:06
【问题描述】:

我正在使用 Redis 为我在内存中存储的模型生成 ID。 Redis 客户端需要回调INCR 命令,这意味着代码看起来像

client.incr('foo', function(err, id) {
  ... continue on here
});

问题是,我已经编写了应用程序的另一部分,它希望 incr 调用是同步的并且只返回 ID,以便我可以像使用它一样

var id = client.incr('foo');

我遇到这个问题的原因是,到目前为止,我只是在内存中使用简单的闭包计数器函数生成 ID,比如

var counter = (function() {
  var count = 0;
  return function() {
    return ++count;
  }
})();

为了简化测试和一般设置。

这是否意味着我的应用在设计上存在缺陷,我需要重写它以期待在生成 ID 时出现回调?或者有什么简单的方法来同步调用?

【问题讨论】:

  • 我认为它不会帮助你,但我已经看到 set 和 incr 不需要回调。 github.com/mranney/node_redis 搜索 "client.set("fooclient.incr("did a thing");
  • @MiaDiLorenzo 仅当您想忽略返回值时,您可以轻松地为set 执行此操作,但不适用于incr,您唯一真正想要的是递增值:)
  • 哦,好的,我现在明白了。否则,您将不得不单独编写一个确实需要回调的 get。

标签: node.js asynchronous redis


【解决方案1】:

Node.js 本质上是一个异步 I/O 库(带有插件)。所以,根据定义,那里没有同步 I/O,你应该重写你的应用程序。

【讨论】:

    【解决方案2】:

    这有点痛苦,但是您要做的就是将生成计数器后的逻辑包装到一个函数中,然后从 Redis 回调中调用它。如果你有这样的事情:

    var id = get_synchronous_id();
    processIdSomehow(id);
    

    你需要做这样的事情。

    var runIdLogic = function(id){
      processIdSomehow(id);
    }
    
    client.incr('foo', function(err, id) {
      runIdLogic(id);
    });
    

    您将需要适当的错误检查,但类似的东西应该适合您。

    Node 有几个顺序编程层(例如TameJS)可能会帮助您实现所需的功能,但它们通常会进行重新编译或类似的事情:您必须确定自己对它的适应程度如果你想使用它们。

    【讨论】:

      【解决方案3】:

      @Sergio 在他的回答中简短地说了这一点,但我想写更多的扩展答案。 node.js 是一种异步设计。它在单个线程中运行,这意味着为了保持快速并处理许多并发操作,所有阻塞调用都必须为其返回值提供回调以异步运行它们。

      这并不意味着同步调用是不可能的。它们是,并且它与您如何信任 3rd 方插件有关。如果有人决定在他们的插件中编写一个阻塞的调用,那么您将受到该调用的支配,它甚至可能是内部的并且没有在他们的 API 中公开的东西。因此,它可以阻止您的整个应用程序。考虑一下如果 Redis 需要大量时间才能返回,然后再乘以可能访问同一例程的客户端数量,会发生什么情况。整个逻辑已经序列化了,都在等待。

      在回答您的最后一个问题时,您不应该努力适应阻止方法。现在看来,这似乎是一个简单的解决方案,但它首先与 node.js 的好处背道而驰。如果您只是更喜欢同步设计工作流程,您可能需要考虑另一个以这种方式设计的框架(使用线程)。如果您想坚持使用 node.js,请重写现有逻辑以符合回调样式。从我看到的代码示例来看,它看起来像是一组嵌套的函数,因为回调使用回调等,直到它可以从该递归堆栈返回。

      【讨论】:

        【解决方案4】:

        node.js 中的应用程序状态通常作为对象传递。我会做的更接近:

        var state = {}
        
        client.incr('foo', function(err, id) {
          state.id = id;
          doSomethingWithId(state.id);
        });
        
        function doSomethingWithId(id) {
          // reuse state if necessary
        }
        

        这只是一种不同的做事方式。

        【讨论】:

          猜你喜欢
          • 2014-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-02
          • 2013-06-05
          • 2013-10-16
          相关资源
          最近更新 更多