angular.js - 怎麼寫promise的鍊式調用
高洛峰
高洛峰 2017-05-15 16:51:30
0
4
506

例如我有一個A.func1()是異步的,它能回傳一個物件x1,我還有一個B.func2()也是異步的,需要根據x1來執行,然後B.func2回傳一個最終值值t ,根據這個最終值t就進行一些提示性顯示。請問這個要怎麼寫呢?
我自己寫的程式碼是這樣的

A.func1().
    then(function(x1) {
        B.func2(x1).
            then(function(t) {
                //do something
            })
    })

但覺得這樣用不用then就一個效果啦…還是變回金字塔了

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

全部回覆(4)
世界只因有你

針對評論裡的補充的“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; }); }) }
世界只因有你

直接在 then 里面返回一个 Promise 的對象,如下:

javascript
A.func1() .then(function (x1) { return B.func2(x1); }) .then(function (t) { // do something });

針對你評論中說的問題,如果不使用第三方的 Promise 庫的話,可以像下面這樣使用:

javascriptvar 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 函式庫可以簡化這個過程。

巴扎黑

promise會傳回promise對象,這樣才使得它可以使用優雅的鍊式呼叫。

过去多啦不再A梦

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对象.
});
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板