Cómo hacer que una función espere hasta que se haya llamado a una devolución de llamada usando node.js

Resuelto Chris asked hace 13 años • 10 respuestas

Tengo una función simplificada que se ve así:

function(query) {
  myApi.exec('SomeCommand', function(response) {
    return response;
  });
}

Básicamente, quiero que llame myApi.execy devuelva la respuesta que se proporciona en la función lambda de devolución de llamada. Sin embargo, el código anterior no funciona y simplemente regresa inmediatamente.

Sólo para un intento muy hack, probé lo siguiente que no funcionó, pero al menos tienes una idea de lo que estoy tratando de lograr:

function(query) {
  var r;
  myApi.exec('SomeCommand', function(response) {
    r = response;
  });
  while (!r) {}
  return r;
}

Básicamente, ¿cuál es una buena forma 'basada en node.js/eventos' de hacer esto? Quiero que mi función espere hasta que se llame a la devolución de llamada y luego devuelva el valor que se le pasó.

Chris avatar Feb 16 '11 05:02 Chris
Aceptado

La forma "buena impulsada por node.js/event" de hacer esto es no esperar .

Como casi todo lo demás cuando se trabaja con sistemas controlados por eventos como node, su función debe aceptar un parámetro de devolución de llamada que se invocará cuando se complete el cálculo. La persona que llama no debe esperar a que se "devuelva" el valor en el sentido normal, sino que debe enviar la rutina que manejará el valor resultante:

function(query, callback) {
  myApi.exec('SomeCommand', function(response) {
    // other stuff here...
    // bla bla..
    callback(response); // this will "return" your value to the original caller
  });
}

Entonces no lo usas así:

var returnValue = myFunction(query);

Pero así:

myFunction(query, function(returnValue) {
  // use the return value here instead of like a regular (non-evented) return value
});
Jakob avatar Feb 15 '2011 22:02 Jakob

Una forma de lograr esto es envolver la llamada API en una promesa y luego usarla awaitpara esperar el resultado.

// Let's say this is the API function with two callbacks,
// one for success and the other for error.
function apiFunction(query, successCallback, errorCallback) {
    if (query == "bad query") {
        errorCallback("problem with the query");
    }
    successCallback("Your query was <" + query + ">");
}

// Next function wraps the above API call into a Promise
// and handles the callbacks with resolve and reject.
function apiFunctionWrapper(query) {
    return new Promise((resolve, reject) => {
        apiFunction(query,(successResponse) => {
            resolve(successResponse);
        }, (errorResponse) => {
            reject(errorResponse);
        });
    });
}

// Now you can use await to get the result from the wrapped api function
// and you can use standard try-catch to handle the errors.
async function businessLogic() {
    try {
        const result = await apiFunctionWrapper("query all users");
        console.log(result);
        
        // the next line will fail
        const result2 = await apiFunctionWrapper("bad query");
    } catch(error) {
        console.error("ERROR:" + error);
    }
}

// Call the main function.
businessLogic();

Producción:

Your query was <query all users>
ERROR:problem with the query
Timo avatar Jul 03 '2018 21:07 Timo

mira esto: https://github.com/luciotato/waitfor-ES6

su código con wait.for: (requiere generadores, --harmony flag)

function* (query) {
  var r = yield wait.for( myApi.exec, 'SomeCommand');
  return r;
}
Lucio M. Tato avatar Dec 06 '2013 14:12 Lucio M. Tato