首先给出一个带有承诺列表的数组:
var promises = [promise1, promise2, promise3];
我希望能够使用谓词执行所有这些承诺。如果第一个谓词返回false,则立即返回给出截至该点已处理的结果并取消所有剩余的Promise。例如:
Promise.all(promises, p => p != false))
.then(results => console.log(results));
结果应该具有直到第一个谓词失败为止要处理的内容。
应按顺序而非并行处理承诺。
答案 0 :(得分:0)
您不能取消承诺。但是,您可以在上一个操作完成后才开始下一个操作:
async function doUntil(generator, predicate) {
const result = [];
let curr;
while(predicate(curr = await generator()))
result.push(curr);
return result;
}
// usable as:
const users = await doUntil(
() => User.getOneAsync(),
user => user.loggedIn
);
为确保可以很容易地将这些承诺应用于承诺列表,但是随后仍然执行那些不属于结果的承诺,结果就毫无用处了:
const promises = [/*...*/];
const result = await doUntil(
() => promises.shift(),
p => p
);
答案 1 :(得分:0)
我的解决方案与Yona的一个Promise非常相似,但是从某种意义上说,您只返回了满足谓词的最后一个返回的Promise值。
在下面的代码中,我简单地构造了一个测试承诺,该承诺在500毫秒后返回一个随机数。然后将随机数传递给谓词,如果该谓词超过0.5,则返回true。
一种改进是,我们尝试捕获承诺可能失败的事件。如果promise失败,则链将立即断开,并返回最后一个结果,类似于promise返回的结果使谓词失败的情况:
// Here we simply set a test promise that returns a random number after 0.5s
function testPromise() {
return new Promise(resolve => {
window.setTimeout(() => resolve(Math.random()), 500);
});
}
// Execute promises in a specified order, evaluate their output by a predicate
async function awaitSequentialPromises(promises, predicate) {
let result;
for (const promise of promises) {
// Try, so that we can catch if a promise fails
try {
const _result = await promise();
console.log(_result);
// Break out of loop if promise returns results that fails predicate
if (!predicate(_result))
break;
else
result = _result;
} catch(e) {
// Break out of loop if promise fails
break;
}
}
console.log(`Final result: ${result}`);
return result;
}
// Our predicate is simply if the promise returns a random number > 0.5
awaitSequentialPromises([testPromise, testPromise, testPromise], v => v > 0.5);
答案 2 :(得分:-1)
这是应该执行您想要的功能。您可能需要修改它,以不同方式处理失败的谓词。
正如其他人指出的那样,您不能“取消”诺言,因为它通常代表已经开始的事情。
/**
* Combines an array of promises with a predicate. Works like Promise.all, but checks each result from the given
* Promise against the supplied predicate, and if the result value from any Promise fails the predicate, the
* overall promise is immediatly resolved with those values which passed the predicate.
*/
function allWithPredicate(
promises /*: Array<Promise<T1>, Promise<T2>, ...> */,
predicate /*: (mostRecentResult, allResults, promiseIndex)*/
) /*: Promise<[T1, T2, ...]> */ {
// Handle empty input arrays
if (promises.length === 0)
return Promise.resolve([]);
// Create a manual result promise, as none of the built-in promise manipulation functions will do the trick.
return new Promise(
(resolve, reject) => {
// This array will collect the values from the promises. It needs to be the same size as the array of
// promises.
const results = new Array(promises.length);
// We track the number of resolved promises so we know when we're done. We can't use the length of the
// array above because the last promise might finish first, which would cause the array to be equal in
// length to the promises array.
let resolvedCount = 0;
// Now we go through each promise and set things up
promises.forEach(
(promise, index) => {
promise.then(
result => {
// A promise has finished successfully! Hooray. We increment the counter.
resolvedCount++;
// Now we check if the newly returned value from the promise is acceptable, using the
// supplied predicate.
if (predicate(result, results, index)) {
// If if it, we keep this result.
results[index] = result;
// If the resolved counter is equal to the original number of promises in the array,
// we are done and can return. Note that we do NOT check against the length of
// the promises array, as it may have been mutated since we were originally called.
if (resolvedCount === results.length) {
resolve(results);
}
} else {
// If not, we short-circuit by resolving the overall promise immediately.
// Note that as written, we do NOT include the unacceptable value in the result.
resolve(results);
}
},
error => {
reject(error);
}
)
}
)
}
);
}
以下是jsbin演示的链接:https://jsbin.com/jasiguredu/edit?js,console
答案 3 :(得分:-2)
Promise.all
仅接受一个论点
var promises = [promise1, promise2, promise3];
Promise.all(promises)
.then(p => {
if(p === false) {
throw new Error(false);
} else {
console.log(p);
}
})
.catch(error => {
console.log(error);
});
}
如果Promise.all中的某个承诺以catch语句结尾,然后完成,那么您可以根据需要在该承诺之外设置一个计数器。