我怎样才能做callback,需要它的子function的信息

我正在使用Node.js作为Haraka (一个smtp服务器)插件的项目。

这是Node.JS,我有一个小问题与callback。 我还没有能够转换这个特定的代码来使用callback。

所以,这是我有的代码:

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

此代码不起作用,因为它不会等待请求的callback继续。 我需要在next()之前完成请求。

这些是要求:

  1. exports.hook_data的结尾必须返回next() 。 但只有在请求后才能返回。
  2. 我需要在add_body_filter返回一个Buffer ,但我需要创build从服务器获取信息的缓冲区。
  3. 获取请求我需要使用一个参数( header ),我只有在add_body_filter

所以问题是,我不能在add_body_filter之前add_body_filter请求,并把结果放在callback中,因为我需要的参数只在add_body_filter里面。

有什么build议吗?

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

我会研究每个要求的基础,看看你是否以不同的方式实现你的目标。

在面值上,只看你在那里的代码,我会寻找一种方法来改变exports.hook_data的约定,这样你就可以在request.getcallback中调用next()

使用Async.js或Promise。

asynchronous实现:

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

这里有很多,我build议你阅读async.js#瀑布的文档。 从本质上讲,它将每个asynchronous调用分解到function块上,并等待它返回,然后继续到下一个块。

同样,因为这些都是asynchronous的,所以Node将这些任务提交给IO事件循环,并且在那里处理(非阻塞)。 当这个线程正在等待时,它可能会在这个请求正在等待的时候移动到下一个请求。

查看交易对象和头对象的哈拉卡手册我没有看到add_body_filter任何依赖add_body_filter 。 此外,您的代码不显示任何依赖add_body_filter 。 所以你的第三个要求看起来无效

考虑到这一点,我认为伪代码(因为我不能testing它)应该为你工作。

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

为了处理你的代码的每个部分的优先级,我使用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进行callback比我认为的其他方式更好。

JavaScript本质上是asynchronous的。 asynchronous是一种编程模式,它提供了非阻塞代码的function,即不停止或不依赖于另一个函数/进程来执行特定的代码行。 Ref: Codementor Article

从维基百科

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

你能做什么?

  1. 使用睡眠/等待,即setTimeout (不推荐)
  2. 使用一些asynchronous库像https://github.com/caolan/async (推荐)
  3. 像Q一样使用一些承诺lib