搜尋

首頁  >  問答  >  主體

angular.js - 怎麼寫promise的鍊式調用

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

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

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

高洛峰高洛峰2743 天前514

全部回覆(4)我來回復

  • 世界只因有你

    世界只因有你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; }); }) }

    回覆
    0
  • 世界只因有你

    世界只因有你2017-05-15 16:53:30

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

    回覆
    0
  • 巴扎黑

    巴扎黑2017-05-15 16:53:30

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

    回覆
    0
  • 过去多啦不再A梦

    过去多啦不再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对象.
    });

    回覆
    0
  • 取消回覆