我能够成功执行Promise.all,并优雅地处理解析和拒绝。但是,有些承诺会在几毫秒内完成,有些可能/可能需要一段时间。
我希望能够为Promise.all中的每个promise设置超时,因此它可以尝试最多花费5秒。
getData() {
var that = this;
var tableUrls = ['http://table-one.com','http://table-two.com'];
var spoonUrls = ['http://spoon-one.com','http://spoon-two.com'];
var tablePromises = that.createPromise(tableUrls);
var spoonPromises = that.createPromise(spoonUrls);
var responses = {};
var getTableData = () => {
var promise = new Promise((resolve, reject) => {
Promise.all(tablePromises.map(that.rejectResolveHandle))
.then((results) => {
responses.tables = results.filter(x => x.status === 'resolved');
resolve(responses);
});
});
return promise;
};
var getSpoonData = () => {
var promise = new Promise((resolve, reject) => {
Promise.all(spoonPromises.map(that.rejectResolveHandle))
.then((results) => {
responses.tables = results.filter(x => x.status === 'resolved');
resolve(responses);
});
});
return promise;
};
return getTableData()
.then(getSpoonData);
}
rejectResolveHandle() {
return promise.then(function(v) {
return {v:v, status: "resolved"};
}, function(e) {
return {e:e, status: "rejected"};
});
}
createPromise(links) {
var promises = [];
angular.forEach(links, function (link) {
var promise = that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
});
promises.push(promise);
});
return promises;
}
我已尝试向createPromise()
添加超时,但这似乎不起作用。将超时设置为300毫秒,一些请求将持续4 +秒:
createPromise(links) {
var promises = [];
angular.forEach(links, function (link) {
var promise = that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
});
promise = new Promise((resolve) => {
setTimeout(() => {
resolve(promise);
}, 300);
});
promises.push(promise);
});
return promises;
}
如果能让事情变得更轻松,我可以访问Bluebird吗?
答案 0 :(得分:8)
这是一个创建Promise.raceAll()
函数的方案,该函数类似于Promise.all()
和Promise.race()
的组合,其中所有承诺都具有超时时间和值,以便承诺在此之前没有解决,它将被短路以解决传入的价值。这基本上将每个承诺放入带有计时器的Promise.race()
。如果计时器获胜,则使用默认值解析承诺。如果原始承诺获胜,则使用实际承诺结果解决。我们使用Promise.race()
来解决第一个完成(超时或原始承诺)。这是Promise.race()
的经典用法(实际上是我曾经真正使用它的唯一实际用途)。
一个典型的例子就是在接下来的15秒内为我提供所有结果。任何花费超过15秒的结果,只需返回null
并等待它们。以下是使这个概念有效的代码:
Promise.delay = function(t, val) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, val), t);
});
}
Promise.raceAll = function(promises, timeoutTime, timeoutVal) {
return Promise.all(promises.map(p => {
return Promise.race([p, Promise.delay(timeoutTime, timeoutVal)])
}));
}
因此,您使用Promise.raceAll()
之类的Promise.all()
,因为您传递了一系列承诺,但您也传递了timeoutTime
和timeoutVal
。 timeoutTime
是在超时承诺之前等待的时间。对于任何超时的承诺,timeoutVal
是结果数组中的内容(通常它会像null
那样容易被识别为非实际结果)。
我不确定我在您的特定代码中完全是您在做什么,但是使用上面的links
代码是
Promise.raceAll(links.map(link => {
return that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
});
}), 5000, null).then(results => {
// process results here
// any timed out values will be null
// you can filter out the timed out results
let final = results.filter(item => !!item);
}).catch(err => {
// process any errors here
});
或者,如果您想确保Promise.raceAll()
获得所有结果,即使某些承诺拒绝,您也可以为每个承诺添加.catch()
处理程序:
Promise.raceAll(links.map(link => {
return that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
}).catch(err => {
// don't let Promise.all() see a reject so it gets all results
return null;
});
}), 5000, null).then(results => {
// process results here
// any timed out values will be null
// you can filter out the timed out or rejected results
let final = results.filter(item => !!item);
}).catch(err => {
// process any errors here
});
答案 1 :(得分:2)
您的尝试只会使用超时承诺覆盖promise
,这意味着HTTP承诺将被完全忽略。
这是您实际使用new Promise
*的相对较少的地方之一:根据HTTP调用创建承诺,解决或拒绝承诺,和拒绝承诺(或解决它,但这似乎很奇怪)超时:
createPromise(links) {
return Promise.all(links.map(function(link) {
return new Promise((resolve, reject) => {
that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
})
.then(resolve)
.catch(reject);
setTimeout(() => {
reject(/*...relevant value here...*/); // Seems like reject to me,
// but you could use resolve
// if you prefer
}, 300);
});
}));
}
(假设map
是一个数组,那就使用links
。)
请注意,一旦为承诺调用了resolve
或reject
,就会完全忽略对后者的后续调用(没有错误或警告)。 (如果这不是真的,我们想要一个上面的标志来跟踪我们是否已经解决了这个承诺。)
* (除非您拥有已启用许可的setTimeout
版本。如果您这样做,则可以像their answer中的jfriend00一样使用Promise.race
。)< / em>的
答案 2 :(得分:0)
一种解决方案可能是将Promise.all
的参数数组中的每个promise转换为超时的promise(比如使用.map
)。超时函数可以根据应用程序需要解析或拒绝提供的参数promise。
使用唯一值在超时后解析承诺允许在提供给Promise.all.then( handler)
此示例着眼于使用辅助函数timedPromise
将承诺转换为已解决的承诺。不包括将promise数组映射到超时promise的数组。
const timedOutValue = new Error( "promise timeout"); // unique value
const timedPromise = (promise, timeout) => {
return new Promise( (resolve, reject) => {
promise.then(resolve, reject);
setTimeout( resolve, timeout, timedOutValue); // could have used reject
});
};
var pendingPromise = new Promise( (resolve,reject) => null); // never settles
timedPromise(pendingPromise)
.then(
data=> console.log( "pendingPromise resolved with %s",
data === timedOutValue ? "timedOutValue" : data),
reason=> console.log( "pendingPromise rejected with %s",
reason === timedOutValue ? "timedOutValue" : reason)
);
&#13;