14

我正在一个将 Node.js 用于Haraka(一个 smtp 服务器)插件的项目中工作。

这是 Node.JS,我在回调方面有一点问题。我无法将此特定代码转换为使用回调。

所以,这是我拥有的代码:

exports.hook_data = function (next, connection) {
    connection.transaction.add_body_filter('', function (content_type, encoding, body_buffer) {
        var header = connection.transaction.header.get("header");
        if (header == null || header == undefined || header == '') return body_buffer;

        var url = 'https://server.com/api?header=' + header ;
        var request = require('request');
        request.get({ uri: url },
          function (err, resp, body) {
              var resultFromServer = JSON.parse(body);
              return ChangeBuffer(content_type, encoding, body_buffer, resultFromServer);
          }
        );
    });
    return next();
}

此代码不起作用,因为它不等待请求的回调继续。我需要先完成请求next()

这些是要求:

  1. 最后exports.hook_data是强制返回next()。但它只需要在请求后返回它。
  2. 我需要返回一个Bufferinadd_body_filter但我需要使用从服务器获取的信息创建缓冲区。
  3. 要发出获取请求,我需要使用header我只有在里面的参数 () add_body_filter

所以问题是我不能在之前发出请求add_body_filter并将结果放在回调中,因为我需要发出请求的参数只在里面add_body_filter

请问有什么建议吗?

4

5 回答 5

4

除非您愿意使用同步的、阻塞的函数,否则不可能满足您编号的要求。

我会检查每个要求背后的原因,看看你是否以不同的方式实现你的目标。

从表面上看,只看你那里的代码,我会寻找一种方法来改变合同,exports.hook_data以便你能够next()从回调内部request.get调用。

于 2015-12-15T20:31:30.017 回答
1

使用 Async.js 或 Promises。

异步实现:

exports.hook_data = function (next, connection) {
  async.waterfall([
    function( done ) {
      connection.transaction.add_body_filter('', function( content_type, encoding, body_buffer ) {
        var header = connection.transaction.header.get("header");
        if ( header == null || header == undefined || header == '' ) {
          done(null, body_buffer);
        }
        done(null, header);
      });
    },
    function( header, done ) {
      var url = 'https://server.com/api?header=' + header;
      var request = require('request');
      request.get({ uri: url },
        function( err, resp, body ) {
          // do something if there's an error
          var resultFromServer = JSON.parse(body);
          done(null, ChangeBuffer(content_type, encoding, body_buffer, resultFromServer));
        }
      );
    }
  ], function( error, buffer ) {
    // do something if there's error
    next(buffer);
  });
}

这里有很多内容,我建议您阅读async.js#waterfall上的文档。本质上,它将每个异步调用分解到它的功能块上,并等待它返回,然后再继续到下一个块。

同样,由于这些都是异步的,Node 将这些任务提交给 IO 事件循环并在那里处理(非阻塞)。当这个线程在等待时,它可能会在这个请求等待时继续下一个请求。

于 2015-12-20T03:43:48.377 回答
0

JavaScript本质上是异步的。异步是一种提供非阻塞代码特性的编程模式,即不停止或不依赖另一个函数/进程来执行特定的代码行。参考:Codementor 文章

来自维基百科

Node.js 提供事件驱动架构和非阻塞 I/O API,旨在优化实时 Web 应用程序的吞吐量和可扩展性

你能做什么?

  1. 使用睡眠/等待,即setTimeout(不推荐)
  2. 使用一些异步库,例如https://github.com/caolan/async(推荐)
  3. 使用像Q这样的承诺库
于 2015-12-24T17:09:22.617 回答
0

为了处理我使用的代码的每个部分的优先级Q,您可以通过几个步骤使用它:

  1. npm install q.

    var request = require('request');
    var Q = require('q');
    
    exports.hook_data = function () {
       var url, header;
       Q()
       .then(function(){
         connection.transaction.add_body_filter('', function(content_type, encoding, body_buffer) {
    
          header = connection.transaction.header.get("header");
    
          if (header == null || header == undefined || header == ''){return body_buffer;}
          url = 'https://server.com/api?header=' + header ;
    
       })
       .then(function(){
    
           request.get({ uri: url }, function (err, resp, body) {
    
               var resultFromServer = JSON.parse(body);
    
               return ChangeBuffer(content_type,encoding,body_buffer,resultFromServer);
           });
    
       })
    
    }
    

async场景中,使用q回调比我认为的其他方式更好。

于 2015-12-24T16:58:09.767 回答
0

查看Transaction 对象Header 对象的 Haraka 手册,我看不到 Header 对add_body_filter. 此外,您的代码对add_body_filter. 所以你的第三个要求看起来无效。

考虑到这一点,我认为以下伪代码(因为我无法测试它)应该适合你。

exports.hook_data = function (next, connection) {
    var header = connection.transaction.header.get("header");
    if (header == null || header == undefined || header == '') {
        return next();

    var url = 'https://server.com/api?header=' + header ;
    var request = require('request');
    request.get({ uri: url },
        function (err, resp, body) {
            var resultFromServer = JSON.parse(body);
            connection.transaction.add_body_filter('', function (content_type, encoding, body_buffer) {
                return ChangeBuffer(content_type, encoding, body_buffer, resultFromServer);
            });
            next();
        }
    );
}

如果 Haraka 手册未能突出 Header 对add_body_filter和/或您根据实际经验发现了它,那么 Quy 的方法似乎是要走的路。

如果您想知道何时使用 next() v/s return next()

于 2015-12-23T13:03:05.787 回答