如何使用$ q.deffer链接ajax请求?

时间:2015-07-31 08:37:06

标签: javascript angularjs asynchronous request promise

我需要这样做:浏览器必须向服务器发出N个请求,请求不能是异步的,下一个请求在先前的请求停止后开始。

我可以用function A写一些for i < N i++并再次递归调用此function A来执行此操作,但它根本不是很漂亮。此外,这称为回调地狱。我想要一些更美丽的解决方案。

我找到了deffered个对象。有人说,它可以帮助我摆脱回调地狱。我想要这样的东西。 setTimeout模仿一个异步请求:

    function foo1(some) {
        debugger;
        setTimeout(function foo1async() {
            debugger;
            deffered.resolve();
        }, 500);
        return deffered.promise;
    }

    function foo2(some) {
        debugger;
        setTimeout(function foo2async() {
            debugger;
            deffered.reject();
        }, 500);
        return deffered.promise;
    }

    function foo3() {
        debugger;
        setTimeout(function foo3async() {
            debugger;
            deffered.resolve();
        }, 500);
        return deffered.promise;
    }

    var deffered;
    function doChain() {
        debugger;
        deffered = $q.defer();
        var promise = deffered.promise;
        promise.then(foo1);
        promise.then(foo2);
        promise.then(foo3);
        promise["finally"](function () {
            debugger;
        });
        deffered.resolve();
    }
  1. 我希望调用foo1,然后调用foo1async并解析deffered对象。
  2. 必须调用
  3. foo2,然后调用foo2async。 3.现在我预计,foo3不会开始,因为foo2async会拒绝被拒绝。之后,我希望在finally部分中调用foo。
  4. 实际上,我有这个: foo1foo2foo3被调用。然后调用finally部分中的foo。然后调用foo1asyncfoo2asyncfoo3async个函数。

    我如何能得到我期待的东西?

    实际上,我会有这样的事情:

    for(var i = 0; i < N; i++) {
        (function (iter) {
            promise.then(function () {
                foo(iter);
            });
        })(i);
    }
    

3 个答案:

答案 0 :(得分:1)

你在这里遇到了一些问题。

首先,您使用延迟将基于回调的异步函数转换为基于承诺的函数 - 但每个函数都需要自己的deferred.promise,因此需要自己的deferred。实际上,我更喜欢使用$q构造函数:

function fooN(input){
  return $q(function(resolve, reject){
    setTimeout(function(){
      resolve(input + "; some more data");
    }, 500);
  });
}

(您也可以使用var deferred = $q.defer()

fooN现在返回一个承诺,因此您不再需要使用$q.defer()

事实上,如果异步函数已经基于承诺,例如$timeout$http,那么您根本不需要deferred,例如:

function fooN(input){
  return $timeout(function(){
    return input + "; some more data";
  }, 500);
})

所以,我们假设foo1foo2foo3的实现方式与fooN一样 - 所有返回的承诺。

要使顺序调用,您需要链接promises - 而不是将多个处理程序附加到某个根承诺。

我会为你分解:

function doChain(){
  var foo1Promise = foo1();
  var foo2AfterFoo1Promise = foo1Promise.then(foo2);
  var foo3AfterFoo2Promise = foo2AfterFoo1Promise.then(foo3);

  var promise = foo3AfterFoo2Promise.then(function(finalData){
    return doSomeProcessing(finalData); // if needed
  });

  promise.catch(function(error){
    // "rethrow", if can't handle
    return $q.reject({msg: "Some error occurred"});
  })

  return promise;
}

或者,同样,更简洁:

function doChain(p){
  return foo1(p)
          .then(foo2)
          .then(foo3)
          .then(function(finalData){
            return doSomeProcessing(finalData);
          })
          .catch(function(error){
            return $q.reject({msg: "Some error occurred"});
          });
}

每个函数的“承诺”返回值是下一个链接函数的输入。

答案 1 :(得分:0)

您可以使用$ q.all方法。例如:

var promises = [promise1, promise2, ...];

$q.all(promises).then(function () {
// do something
});

答案 2 :(得分:0)

现在发生的是所有foo *承诺都取决于单promise;当它被解决时,所有都被触发。在ASCII艺术中,依赖关系是:

        ┎ foo1
promise ╁ foo2
        ┖ foo3

你想要的是:

function doChain() {
    foo1()
        .then(foo2)
        .then(foo3)
    ;
}

无需额外的promise。也没有回调地狱!