显式传递
与嵌套回调类似,此技术依赖于闭包。但是,链条保持不变-不仅传递最新结果,还为每个步骤传递了一个状态对象。这些状态对象会累积先前操作的结果,并传回以后将再次需要的所有值以及当前任务的结果。
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
});
}
在这里,那个小箭头b => [resultA, b]
是关闭函数,resultA
并将两个结果的数组传递给下一步的函数。它使用参数解构语法将其再次分解为单个变量。
在ES6进行销毁之前.spread()
,许多Promise库(Q,Bluebird,when,…)提供了一种漂亮的辅助方法。它需要一个具有多个参数的函数(每个数组元素一个)用作.spread(function(resultA, resultB) { …
。
当然,此处所需的关闭可以通过一些辅助功能进一步简化,例如
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));
另外,您可以雇用Promise.all
为数组产生promise:
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
});
}
您不仅可以使用数组,还可以使用任意复杂的对象。例如,使用_.extend
或Object.assign
在其他辅助函数中:
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
});
}
尽管此模式保证了扁平链,而显式状态对象可以提高清晰度,但是对于长链而言,它将变得乏味。特别是当您仅偶尔需要状态时,您仍然必须将其传递给每一步。有了这个固定的接口,链中的单个回调就紧密地耦合在一起并且不灵活地进行更改。这使得分解单个步骤变得更加困难,并且回调不能直接从其他模块提供-始终需要将它们包装在关心状态的样板代码中。像上面这样的抽象辅助函数可以减轻一些痛苦,但是它总是存在的。
javascript
,它也与其他语言相关。我只是在java和jdeferred中使用“打破链条”答案