例如我有一個A.func1()是異步的,它能回傳一個物件x1,我還有一個B.func2()也是異步的,需要根據x1來執行,然後B.func2回傳一個最終值值t ,根據這個最終值t就進行一些提示性顯示。請問這個要怎麼寫呢?
我自己寫的程式碼是這樣的
A.func1().
then(function(x1) {
B.func2(x1).
then(function(t) {
//do something
})
})
但覺得這樣用不用then就一個效果啦…還是變回金字塔了
世界只因有你2017-05-15 16:53:30
針對評論裡的補充的“promise連續調用過程中保存狀態”,我想詳細說幾種策略
也就是調整你的邏輯,讓A.func1,B.func2,和後面那個匿名函數(就叫func3吧)的呼叫過程不含狀態,也就是讓func3只依賴func2的輸出,不依賴func1的輸出;又或著讓func2不依賴func1,用類似Promise.all
來同時拿到func1和func2的結果丟給func3
優點:state可擴充state.x2 .x3 ...
問題:很長的呼叫鏈帶複雜狀態的話,很容易污染出bug,程式碼可維護性下降嚴重
js
function yourLogic() { var state = {}; return A.func1() .then(function(x1) { state.x1 = x1; return B.func2(x1); }) .then(function(t) { //play with t & state.x1 return yourResult; }); }
bluebird
的bind方法可以綁定thisArg,可以用來保留狀態,原理是一樣的
js
function yourLogic() { return A.func1() .bind({})//新建空对象用于保留状态 .then(function(x1) { this.x1 = x1; return B.func2(x1); }) .then(function(t) { //play with t & this.x1 return yourResult; }); }
優點:不帶狀態,如果呼叫鏈很長,這個額外狀態被控制在兩步驟之間,保持了較好的可維護性,不易出bug
缺點:如果長調用鏈的每步都有狀態,會變得無比囉嗦
js
function yourLogic() { return A.func1() .then(function(x1) { return B.func2(x1) .then(function(t) { return { t: t, x1: x1 } }); }) .then(function(state) { //play with state.t & state.x1 return yourResult; }); }
當然這裡的內層then也可以自己包裝一下優化掉
js
function yourLogic() { return A.func1() .then(function(x1) { return keepState(B.func2(x1), { x1: x1 }, 't'); }) .then(function(state) { //play with state.t & state.x1 return yourResult; }); } function keepState(promise, state, key) { return promise.then(function(value) { state[key] = value; return state; }); }
其實就是題主原來的寫法,我覺得主要的問題就是題主說的又降級回到了原本的“callback hell”或者說回調金字塔的難堪之中了
優點是…it works
js
function yourLogic() { return A.func1() .then(function(x1) { return B.func2(x1) .then(function(t) { //play with t & x1 return yourResult; }); }) }
世界只因有你2017-05-15 16:53:30
直接在 then
里面返回一个 Promise
的對象,如下:
javascript
A.func1() .then(function (x1) { return B.func2(x1); }) .then(function (t) { // do something });
針對你評論中說的問題,如果不使用第三方的 Promise
庫的話,可以像下面這樣使用:
javascript
var promise = new Promise(function (resolve, reject) { var firstValue; A.func1() .then(function (x1) { firstValue = x1; // 临时保存 return B.func2(x1); }, reject) .then(function (x2) { resolve({ firstValue: firstValue, secondValue: x2 }); }, reject); }); promise.then(function (result) { console.log(result); // {"firstValue": "Hello", "secondValue": "World"} });
使用第三方的 Promise
函式庫可以簡化這個過程。
过去多啦不再A梦2017-05-15 16:53:30
then裡面的函數的返回值如果是一個直接量,則會作為下一個鍊式調用的then的參數
如果返回值具有promise的接口,則返回該promise的resolve的結果
用q做個例子
var q = require('q');
var a = function(){
var d = q.defer();
d.resolve(1);
return d.promise;
};
a().then(function(r){
console.log(r); // 此处是1
return 2;
}).then(function(r){
console.log(r); // 此处2,是由上一个then返回的
var d = q.defer();
d.resolve(3);
return d.promise;
}).then(function(r){
console.log(r); // 此处是3,由上一个then返回的promise的resolve提供.当需要异步调用时直接return的值肯定不够用,这时就需要返回promise对象.
});