Cuándo hacer una función diferida usando Promesas

Estoy usando la biblioteca de nodos Q para Promesas, pregunta que creo que también se puede aplicar a la lib de Bluebird.

Contexto

Tengo que realizar algunas llamadas de función a mis propias funciones personalizadas y a las funciones asíncronas de node.js fs style.

Si estoy haciendo una llamada a una función como esta:

función de sincronización

 do_something = function (input) { // assign variables, do other sync stuff } 

y necesita que lo anterior tenga lugar before esta función:

función de sincronización

 do_something_else = function (input) { // assign variable, do other sync stuff } 

y then necesita llamar a una función de nodo nativo similar a:

función asíncrona

 writeData = function (obj, callback) { var deferred = Q.defer(); fs.writeFile(obj.file, obj.datas, function (err, result) { if (err) deferred.reject(err); else deferred.resolve('write data completed'); }); return deferred.promise.nodeify(callback); } 

y finally necesita que lo anterior tenga lugar before esta función:

función de sincronización

 do_something_last = function (input) { // assign variable, do other sync stuff } 

Pregunta

¿Lo que hay que hacer aquí es hacer que todas mis funciones sean “diferidas” o comprometidas para que pueda asegurarme de que se llamen en secuencia o en el orden correcto? al igual que:

 do_something(variable) .then(do_something_else) .then(writeData) .then(do_something_last) .done(); 

¿O debería hacer esto en lugar de eso y mantener el orden (secuenciación)? Al igual que:

 var variable1 = 'test1.txt' var variable2 = 'test2.txt' var return_value = do_something(variable1); var return_another_value = do_something_else(return_value); <--sync writeData(return_another_value); <-- async function var final_value = do_something_last(variable2); <-- sync function // could potentially have async calls again after a sync call writeDataAgain(return_another_value); <-- async function 

Aclaraciones

Lo que pensé era que, dado que algunas de estas funciones de sincronización tendrán que activarse después del asíncrono, tuve que hacerlas conscientes de Promise para mantener la secuencia recta, así:

Las funciones de sincronización se han hecho realidad.

 do_something = function (input) { var deferred = Q.defer(); // assign variables, do other sync stuff deferred.resolve(_output_result_); return deferred.promise; } do_something_else = function (input) { var deferred = Q.defer(); // assign variables, do other sync stuff deferred.resolve(_output_result_); return deferred.promise; } do_something_last = function (input) { var deferred = Q.defer(); // assign variables, do other sync stuff deferred.resolve('completed workflow'); return deferred.promise; } 

esto me permitiría hacer esto:

 do_something(variable) .then(do_something_else) <-- these need to execute before writeData .then(writeData) <-- a async node fs call to writeFile .then(do_something_last) <-- I need this to happen after the writeDate .done(); 

Después de los comentarios que he leído, supongo que lo que parece que realmente estoy preguntando es:

¿Cómo creo un flujo de trabajo de función, mezclando llamadas de funciones asíncronas sin sincronización de promesas y sin compromiso, al mismo tiempo que se mantiene el orden (o secuenciación) de la ejecución?

solo haz esto en lugar de eso y sigue así ordenando:

 writeData(return_another_value); var final_value = do_something_last(variable2); 

Bueno, eso simplemente no funcionará, ya que do_something_last no se llama después de que se resuelva la promesa writeData(…) . Simplemente comenzará justo después de que la promesa sea creada y devuelta. Entonces, si te preocupa ese pedido en particular y quieres esperar hasta que se escriban los datos, entonces debes usarlos con una callback:

 var final_promise = writeData(return_another_value).then(function(writeResult) { return do_something_last(variable2); }); 

Las reglas generales son:

  • sincronice las funciones sincrónicas, sin necesidad de promesas
  • Hacer que todas las funciones asíncronas siempre devuelvan una promesa.
  • use diferidos solo en el nivel más bajo posible para promisificación

Simplemente puede colocar funciones síncronas en una cadena , los valores de retorno no prometedores (o incluso las excepciones lanzadas) funcionan bien en ellos. Así que mientras puedes escribir tu secuencia como

 Q('test1.txt') .then(do_something) .then(do_something_else) .then(writeData) .then(do_something_last.bind(null, 'test2.txt')) .done(); 

parece bastante extraño Si no planea hacer que el do_something asíncrono en un futuro cercano por alguna razón, a menudo es más sencillo escribir y leer

 writeData(do_something_else(do_something('test1.txt'))).then(function() { return do_something_last('test2.txt'); }).done(); 

Es cierto que a veces es más atractivo escribir

 somePromise() .then(doSomethingSynchronous) .then(doSomethingAsynchronous) 

que

 somePromise .then(function(res) { return doSomethingAsynchronous(doSomethingSynchronous(res)); }) 

aunque sean funcionalmente idénticos . Elige el estilo que más te guste y que sea más consistente.

Si todo lo que te importa es si tus funciones van en secuencia o no, haz esto:

 do_something(variable) .then(do_something_else) .then(writeData) .then(do_something_last) .done(); 

Solo asignará promesas a las variables cuando las vaya a pasar (por ejemplo, a otros servicios), o las utilice para crear diferentes cadenas de promesas.

p.ej

 var promise = do_something('123') // two different promise chains var task1 = promise.then(function(res){ // logic }) var task2 = promise.then(function(res){ // other logic, independent from task1 })