Quand faire une fonction différée en utilisant Promises

J’utilise la bibliothèque de nœuds Q pour Promises. Cette question peut également s’appliquer à la bibliothèque Bluebird.

Le contexte

J’ai quelques appels de fonction à effectuer à la fois pour mes propres fonctions personnalisées et pour les fonctions asynchrones de style node.js.

si j’appelle une fonction comme celle-ci:

fonction de synchronisation

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

et il faut que ce qui précède ait lieu before cette fonction:

fonction de synchronisation

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

et then besoin d’appeler une fonction de nœud natif semblable à:

fonction asynchrone

 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); } 

et finally avoir besoin de ce qui précède before cette fonction:

fonction de synchronisation

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

Question

Est-ce que la ‘bonne’ chose à faire ici, de rendre toutes mes fonctions ‘différées’ ou de promesse conscientes afin que je puisse m’assurer qu’elles sont appelées dans l’ordre ou dans le bon ordre? ainsi:

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

ou dois-je simplement faire cela à la place et conserver l’ordre (séquencement)? Ainsi:

 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 

Des clarifications

Ce que je pensais, étant donné que certaines fonctions de synchronisation devant être activées après l’async, je devais les mettre au courant de Promise afin de maintenir la séquence droite, comme suit:

les fonctions de synchronisation sont au courant des promesses

 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; } 

cela me permettrait de faire ceci:

 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(); 

Après les commentaires que j’ai lus, je suppose que ce que je demande vraiment, c’est:

Comment créer un stream de travail de fonction combinant des appels de fonction asynchrone synchrone sans promesse et synchrone de promesse tout en conservant l’ordre (ou le séquencement) de l’exécution?

faites simplement ceci à la place et gardez la commande comme ceci:

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

Cela ne fonctionnera tout simplement pas, car do_something_last n’est pas appelé après la writeData(…) la writeData(…) . Cela commencera juste après la création et le retour de la promesse. Donc, si vous vous souciez de cet ordre et que vous voulez attendre que les données soient écrites, vous devez then utiliser avec un rappel:

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

Les règles générales sont les suivantes:

  • rendre les fonctions synchrones synchrones – pas besoin de promesses
  • faire en sorte que toutes les fonctions asynchrones renvoient toujours une promesse
  • utiliser les crédits différés uniquement au niveau le plus bas possible à des fins de promisification

Vous pouvez simplement placer des fonctions synchrones dans une chaîne then , des valeurs de retour non promises (ou même des exceptions levées) fonctionnent correctement. Ainsi, alors que vous pouvez écrire votre séquence comme

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

cela semble plutôt étrange. Si, pour une raison quelconque, vous n’avez pas l’intention de rendre le do_something asynchrone dans un avenir proche, il est souvent plus simple d’écrire et de lire

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

Certes, il est parfois plus attrayant d’écrire

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

que

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

même s’ils sont fonctionnellement identiques . Choisissez le style que vous préférez et qui est plus cohérent.

Si tout ce qui vous importe est de savoir si vos fonctions vont dans l’ordre ou non, alors procédez comme suit:

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

Vous n’atsortingbuez des promesses à des variables que lorsque vous les transmettez (par exemple à d’autres services) ou que vous les utilisez pour créer différentes chaînes de promesses.

par exemple

 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 })