Pass-through explicite
Semblable à l'imbrication des rappels, cette technique repose sur des fermetures. Pourtant, la chaîne reste plate - au lieu de ne transmettre que le dernier résultat, un objet d'état est transmis à chaque étape. Ces objets d'état accumulent les résultats des actions précédentes, transmettant à nouveau toutes les valeurs qui seront nécessaires plus tard, ainsi que le résultat de la tâche en cours.
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(b => [resultA, b]); // function(b) { return [resultA, b] }
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Ici, cette petite flèche b => [resultA, b]
est la fonction qui se ferme resultA
et passe un tableau des deux résultats à l'étape suivante. Qui utilise la syntaxe de déstructuration des paramètres pour le diviser à nouveau en variables uniques.
Avant que la déstructuration ne soit disponible avec ES6, une méthode astucieuse d'aide appelée .spread()
était fournie par de nombreuses bibliothèques de promesses ( Q , Bluebird , quand ,…). Il prend une fonction avec plusieurs paramètres - un pour chaque élément du tableau - à utiliser comme .spread(function(resultA, resultB) { …
.
Bien sûr, cette fermeture nécessaire ici peut être encore simplifiée par certaines fonctions d'aide, par exemple
function addTo(x) {
// imagine complex `arguments` fiddling or anything that helps usability
// but you get the idea with this simple one:
return res => [x, res];
}
…
return promiseB(…).then(addTo(resultA));
Alternativement, vous pouvez utiliser Promise.all
pour produire la promesse du tableau:
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return Promise.all([resultA, promiseB(…)]); // resultA will implicitly be wrapped
// as if passed to Promise.resolve()
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Et vous pouvez non seulement utiliser des tableaux, mais aussi des objets arbitrairement complexes. Par exemple, avec _.extend
ou Object.assign
dans une fonction d'assistance différente:
function augment(obj, name) {
return function (res) { var r = Object.assign({}, obj); r[name] = res; return r; };
}
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(augment({resultA}, "resultB"));
}).then(function(obj) {
// more processing
return // something using both obj.resultA and obj.resultB
});
}
Bien que ce motif garantisse une chaîne plate et que les objets d'état explicites puissent améliorer la clarté, il deviendra fastidieux pour une longue chaîne. Surtout lorsque vous n'avez besoin que de l'état de façon sporadique, vous devez toujours le passer à chaque étape. Avec cette interface fixe, les rappels uniques dans la chaîne sont assez étroitement couplés et inflexibles à changer. Cela rend l'affacturage des étapes simples plus difficile, et les rappels ne peuvent pas être fournis directement à partir d'autres modules - ils doivent toujours être enveloppés dans du code passe-partout qui se soucie de l'état. Les fonctions d'aide abstraite comme celles ci-dessus peuvent atténuer un peu la douleur, mais elles seront toujours présentes.
javascript
, elle est pertinente dans une autre langue. J'utilise juste la réponse "casser la chaîne" en java et jdeferred