在promise库 Q 中,您可以执行以下操作来按顺序链接承诺:
var items = ['one', 'two', 'three'];
var chain = Q();
items.forEach(function (el) {
chain = chain.then(foo(el));
});
return chain;
但是,以下内容不适用于 $ q :
var items = ['one', 'two', 'three'];
var chain = $q();
items.forEach(function (el) {
chain = chain.then(foo(el));
});
return chain;
答案 0 :(得分:36)
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(...);
注意:
.reduce
是原始javascript,不是库的一部分。result
是先前的异步结果/数据,包含在内以保证完整性。最初的result
是initialValue
。如果没有必要通过`结果,那么就把它留下来。$q.when(initialValue)
。doSomethingAsync
是foo
(或者foo()返回什么?) - 无论如何,是一个函数。如果你像我一样,那么乍一看,这种模式看起来就像一个难以理解的污垢,但是一旦你的眼睛变得协调,你就会开始认为它是一个老朋友。
修改强>
这是一个demo,旨在证明上面推荐的模式实际上是按顺序执行其doSomethingAsync()
调用,而不是在构建链时立即执行,如下面的评论所示。
答案 1 :(得分:28)
只需使用$ q.when()函数:
var items = ['one', 'two', 'three'];
var chain = $q.when();
items.forEach(function (el) {
chain = chain.then(foo(el));
});
return chain;
注意: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;
答案 2 :(得分:4)
或许比redgeoff's answer更简单,如果您不需要自动化,则可以使用$q.when()
与.then()
结合使用来链接承诺,如
return $q.when()
.then(function(){ return promise1; })
.then(function(){ return promise2; });
所示{3}}。
URI uri = new URIBuilder().setScheme("https")
.setHost("somehost.com")
.setPath("/API/v1/export").build();
HttpPost post = new HttpPost(uri);
post.setHeader("X-API-ID", "myId");
post.setHeader("Accept", "application/json");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("format", "csv"));
params.add(new BasicNameValuePair("userId", "userId"));
post.setEntity(new UrlEncodedFormEntity(params));
JsonNode responseJson = sendResponseEngineRequest(post);
答案 3 :(得分:4)
有这个:
let items = ['one', 'two', 'three'];
一行(好,3为可读性):
return items
.map(item => foo.bind(null, item))
.reduce($q.when, $q.resolve());
答案 4 :(得分:4)
var when = $q.when();
for(var i = 0; i < 10; i++){
(function() {
chain = when.then(function() {
return $http.get('/data');
});
})(i);
}
答案 5 :(得分:2)
我更喜欢使用angular.bind
(或Function.prototype.bind
)准备将返回承诺的函数,然后使用reduce快捷键将它们链接到链中。例如
// getNumber resolves with given number
var get2 = getNumber.bind(null, 2);
var get3 = getNumber.bind(null, 3);
[get2, get3].reduce(function (chain, fn) {
return chain.then(fn);
}, $q.when())
.then(function (value) {
console.log('chain value =', value);
}).done();
// prints 3 (the last value)
答案 6 :(得分:1)
你的答案是对的。但是,我认为我提供了另一种选择。如果你发现自己经常串联链接承诺,你可能会对$ q.serial感兴趣。
var items = ['one', 'two', 'three'];
var tasks = items.map(function (el) {
return function () { foo(el, (items.length - i)*1000)); });
});
$q.serial(tasks);
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);
});
};
}