我怎样才能做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()
之前完成请求。
这些是要求:
- 在
exports.hook_data
的结尾必须返回next()
。 但只有在请求后才能返回。 - 我需要在
add_body_filter
返回一个Buffer
,但我需要创build从服务器获取信息的缓冲区。 - 获取请求我需要使用一个参数(
header
),我只有在add_body_filter
。
所以问题是,我不能在add_body_filter
之前add_body_filter
请求,并把结果放在callback中,因为我需要的参数只在add_body_filter
里面。
有什么build议吗?
除非你愿意使用同步,阻塞function,否则不可能满足你编号的要求。
我会研究每个要求的基础,看看你是否以不同的方式实现你的目标。
在面值上,只看你在那里的代码,我会寻找一种方法来改变exports.hook_data
的约定,这样你就可以在request.get
callback中调用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
,你可以在几个步骤中使用它:
-
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应用程序的可伸缩性
你能做什么?
- 使用睡眠/等待,即
setTimeout
(不推荐) - 使用一些asynchronous库像https://github.com/caolan/async (推荐)
- 像Q一样使用一些承诺lib