javascript - smart - ¿Cómo puedo hacer una devolución de llamada que requiera información de su función secundaria?
solidity español (5)
JavaScript es de naturaleza asincrónica. Asincrónico es un patrón de programación que proporciona la característica del código no bloqueante, es decir, no se detiene o no depende de otra función / proceso para ejecutar una línea particular de código. Ref .: Artículo Codementor
De Wikipedia
Node.js proporciona una arquitectura impulsada por eventos y una API de E / S sin bloqueo diseñada para optimizar el rendimiento y la escalabilidad de una aplicación para aplicaciones web en tiempo real
¿Qué puedes hacer?
- Use un sleep / wait, es decir,
setTimeout
(No recomendado) - Usa alguna biblioteca asíncrona como https://github.com/caolan/async (recomendado)
- Use alguna promesa lib como Q
Estoy trabajando en un proyecto que usa Node.js para un plugin Haraka (un servidor smtp).
Esto es Node.JS y tengo un pequeño problema con callbacks. No he podido convertir este código en particular para usar una devolución de llamada.
Entonces, este es el código que tengo:
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();
}
Este código no funciona porque no espera la devolución de la solicitud para continuar. Necesito finalizar la solicitud antes del next()
;
Y estos son los requisitos:
- Al final de
exports.hook_data
es obligatorio volver anext()
. Pero solo tiene que devolverlo después de la solicitud. - Necesito devolver un
Buffer
enadd_body_filter
pero necesito crear el buffer con la información obtenida de un servidor. - Para hacer la solicitud de
add_body_filter
necesito usar un parámetro (header
) que solo tengo dentro deadd_body_filter
.
Entonces, el problema es que no puedo hacer la solicitud antes de add_body_filter
y poner el resultado dentro de una devolución de llamada porque el parámetro que necesito para hacer la solicitud está solo dentro de add_body_filter
.
¿Algún consejo, por favor?
A menos que esté dispuesto a usar funciones de bloqueo síncronas, es imposible satisfacer los requisitos que tiene numerados.
Examinaré las razones subyacentes a cada requisito y veré si logras tus objetivos de una manera diferente.
En el valor nominal, mirando solo el código que tienes allí, buscaría una forma de alterar el contrato de exports.hook_data
para que puedas llamar a next()
desde adentro de la callback de request.get
.
Mirando el manual de Haraka para el objeto de transacción y el objeto de encabezado , no veo que haya ninguna dependencia de encabezado en add_body_filter
. Además, su código no muestra ninguna dependencia en add_body_filter
. Por lo tanto, su tercer requisito parece no válido.
Teniendo eso en cuenta, creo que seguir un pseudocódigo (ya que no puedo probarlo) debería funcionar para ti.
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();
}
);
}
Si el manual de Haraka no ha resaltado la dependencia de Header en add_body_filter
y / o lo ha descubierto en función de su experiencia práctica, entonces el enfoque de Quy parece ser el camino a seguir.
Si se pregunta cuándo usar next () v / s return next ()
Para manejar la prioridad de cada parte de tu código, uso Q
, puedes usarlo en algunos pasos:
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); }); }) }
En escenarios async
, usar q
para devoluciones de llamadas es mucho mejor que otras formas, creo.
Use Async.js o Promises.
Implementación Async:
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);
});
}
Aquí hay mucho y te recomiendo que leas los documentos sobre la cascada de async.js # . Básicamente, divide cada llamada asincrónica en su bloque funcional y espera a que vuelva antes de continuar al siguiente bloque.
Nuevamente, dado que todos son asincrónicos, Node envía estas tareas al ciclo de eventos IO y se encarga de eso (sin bloqueo). Cuando este hilo está esperando, probablemente pasará a la siguiente solicitud mientras esta solicitud está en espera.