admin管理员组文章数量:1356426
I am working in a project that uses Node.js for a Haraka (an smtp server) plugin.
This is Node.JS and I have a little problem whith callbacks. I haven't been able to convert this particular code to use a callback.
So, this is the code that I have:
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 = '=' + 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();
}
This code does not work because It doesn't wait the callback of the Request to continue. I need to finish the request before next()
;
And these are the requirements:
- At the end of
exports.hook_data
is mandatory to returnnext()
. But it only have to return it after the request. - I need to return a
Buffer
inadd_body_filter
but I need to create the buffer with information getted from a server. - To make the Get Request I need to use a parameter (
header
) that I only have insideadd_body_filter
.
So the issue is that I can not make the request before add_body_filter
and put the result inside a callback because the parameter that I need to make the request are only inside add_body_filter
.
Any advice please?
I am working in a project that uses Node.js for a Haraka (an smtp server) plugin.
This is Node.JS and I have a little problem whith callbacks. I haven't been able to convert this particular code to use a callback.
So, this is the code that I have:
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./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();
}
This code does not work because It doesn't wait the callback of the Request to continue. I need to finish the request before next()
;
And these are the requirements:
- At the end of
exports.hook_data
is mandatory to returnnext()
. But it only have to return it after the request. - I need to return a
Buffer
inadd_body_filter
but I need to create the buffer with information getted from a server. - To make the Get Request I need to use a parameter (
header
) that I only have insideadd_body_filter
.
So the issue is that I can not make the request before add_body_filter
and put the result inside a callback because the parameter that I need to make the request are only inside add_body_filter
.
Any advice please?
Share Improve this question asked Dec 15, 2015 at 20:16 Ricardo Polo JaramilloRicardo Polo Jaramillo 12.3k13 gold badges62 silver badges85 bronze badges 13- 1 You can't use an async function in Javascript, but demand that it behave synchronously. That is simply NOT possible. If you have an async operation, then you MUST code to use it asynchronously. That means returning results in a promise or via a callback, NOT via the return value from the function because the function will return BEFORE the async operation is even plete. You would probably benefit from reading this How to return response from asynchronous operation. – jfriend00 Commented Dec 15, 2015 at 22:30
-
Can you pass a callback to
ChangeBuffer
? – Alexander Elgin Commented Dec 18, 2015 at 7:00 -
And where do you use
body_buffer
(see the line #4) and the result ofChangeBuffer(content_type, encoding, body_buffer, resultFromServer)
(see the line #11) which you return? I guess nowhere, right? – Alexander Elgin Commented Dec 18, 2015 at 7:22 -
@AlexanderElgin the return of
add_body_filter
is a buffer, this buffer contains the body of an email. I dont use it directly, the server uses it when processing an email. I write ChangeBuffer so I can pass a callback If needed. – Ricardo Polo Jaramillo Commented Dec 18, 2015 at 12:51 - Can you use Async.js or Promises to control the flow? Otherwise, you'll just end up with a really hacky solution to be honest. – Quy Commented Dec 20, 2015 at 3:23
5 Answers
Reset to default 4Unless you are willing to use synchronous, blocking functions, it is impossible to satisfy the requirements you have numbered.
I would examine reasons underlying each requirement and see if you acplish your goals in a different way.
On face value, looking at just the code you have there, I would look for a way to alter the contract of exports.hook_data
so that you're able to call next()
from inside the request.get
callback.
Use Async.js or Promises.
Async implementation:
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./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);
});
}
There's a lot here and I remend you reading the docs on async.js#waterfall. Essentially it breaks up each async call into it's on function block and waits for it to return before it continues onto the next block.
Again, since these are all async, Node submits these tasks to the IO event loop and it's taken care of there (non-blocking). When this thread is waiting, it'll probably move on to the next request while this request is waiting.
Looking at the Haraka manual for Transaction object & Header object I don't see there is any dependency of Header on add_body_filter
. Also your code doesn't show any dependency on add_body_filter
. So your 3rd requirement looks invalid.
Considering that, I think following pseudocode(as I can't test it) should work for you.
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./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();
}
);
}
If Haraka manual has failed to highlight the dependency of Header on add_body_filter
and / or you have discovered it based on your practical experience, then Quy's approach seems to be the way to go.
If you are wondering when to use next() v/s return next()
For handling priority of each part of your code I use Q
, You can use it in few steps:
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./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); }); }) }
In async
scenarios, using q
for callbacks is more better than other ways I think.
JavaScript is asynchronous in nature. Asynchronous is a programming pattern which provides the feature of non-blocking code i.e do not stop or do not depend on another function / process to execute a particular line of code. Ref: Codementor Article
From Wikipedia
Node.js provides an event-driven architecture and a non-blocking I/O API designed to optimize an application's throughput and scalability for real-time web applications
What can you do?
- Use a sleep/wait ie
setTimeout
(Not remended) - Use some async lib like https://github./caolan/async (Remended)
- Use some promise lib like Q
本文标签: javascriptHow can I make a callback that requires info of its child functionStack Overflow
版权声明:本文标题:javascript - How can I make a callback that requires info of its child function - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743974179a2570810.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论