如何使用angularjs $ q顺序链接promise?

red*_*off 15 chaining sequential angularjs q angular-promise

在promise库Q中,您可以执行以下操作来按顺序链接promise:

var items = ['one', 'two', 'three'];
var chain = Q();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;
Run Code Online (Sandbox Code Playgroud)

但是,以下内容不适用于$ q:

var items = ['one', 'two', 'three'];
var chain = $q();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;
Run Code Online (Sandbox Code Playgroud)

Roa*_*888 37

Redgeoff,你自己的答案就是我用来将数组翻译成链式系列承诺的方式.

紧急事实上的模式如下:

function doAsyncSeries(arr) {
    return arr.reduce(function (promise, item) {
      return promise.then(function(result) {
        return doSomethingAsync(result, item);
      });
    }, $q.when(initialValue));
}

//then
var items = ['x', 'y', 'z'];
doAsyncSeries(items).then(...);
Run Code Online (Sandbox Code Playgroud)

笔记:

  • .reduce 是原始的javascript,不是库的一部分.
  • result是以前的异步结果/数据,包含在内以保证完整性.最初的resultinitialValue.如果没有必要通过`结果,那么就把它留下来.
  • $q.when(initialValue)根据您使用的lib承诺进行调整.
  • 在你的情况下,doSomethingAsyncfoo(或什么foo()返回?) - 无论如何,一个函数.

如果你像我一样,那么乍一看,这种模式看起来就像一个难以理解的污垢,但是一旦你的眼睛变得协调,你就会开始认为它是一个老朋友.

编辑

这是一个演示,旨在演示上面推荐的模式确实doSomethingAsync()按顺序执行其调用,而不是在构建链时立即执行,如下面的注释所示.


red*_*off 32

只需使用$ q.when()函数:

var items = ['one', 'two', 'three'];
var chain = $q.when();
items.forEach(function (el) {
  chain = chain.then(foo(el));
});
return chain;
Run Code Online (Sandbox Code Playgroud)

注意:foo必须是工厂,例如

function setTimeoutPromise(ms) {
  var defer = $q.defer();
  setTimeout(defer.resolve, ms);
  return defer.promise;
}

function foo(item, ms) {
  return function() {
    return setTimeoutPromise(ms).then(function () {
      console.log(item);
    });
  };
}

var items = ['one', 'two', 'three'];
var chain = $q.when();
items.forEach(function (el, i) {
  chain = chain.then(foo(el, (items.length - i)*1000));
});
return chain;
Run Code Online (Sandbox Code Playgroud)

  • 这不起作用.它同时执行所有这些操作.我知道这是因为我执行了一系列约需500 MS的请求.看着我的网络流量,他们都同时出去(但是按顺序). (4认同)

pab*_*oRN 5

var when = $q.when();

for(var i = 0; i < 10; i++){
    (function() {
         chain = when.then(function() {
        return $http.get('/data');
      });

    })(i); 
}
Run Code Online (Sandbox Code Playgroud)