suchen

Heim  >  Fragen und Antworten  >  Hauptteil

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就一个效果啦……还是变回金字塔了

高洛峰高洛峰2776 Tage vor543

Antworte allen(4)Ich werde antworten

  • 世界只因有你

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

    Antwort
    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 库可以简化这个过程。

    Antwort
    0
  • 巴扎黑

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

    promise会返回promise对象,这样才使得它可以使用优雅的链式调用。

    Antwort
    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对象.
    });

    Antwort
    0
  • StornierenAntwort