在 javascript 中的循环内外有条件地链接承诺
Conditionally chaining promises inside and outside of a loop in javascript
在下面的代码中,当循环内的条件满足时,我们无法真正确定两个 asyncFunction 的调用顺序。
siblings.forEach(function(sibling, index) {
// This condition may only be satisfied once (only one sibling may have data-selected true)
if (sibling.getAttribute('data-selected') == 'true') {
asyncFunction(sibling);
}
})
asyncFunction(element);
因为我知道 asyncFunction() returns 一个 promise 我可以将它们链接起来以确保顺序:
asyncFunction(sibling).then(asyncFunction(element));
但是如何在考虑条件的情况下做到这一点?
我考虑过将循环包装在一个 promise 中,该 promise 在满足条件时或在循环结束后解析,但它似乎有点令人费解。
// Untested
function checkSiblings(siblings) {
let promise = new Promise(function(resolve, reject) {
siblings.forEach(function(sibling, index) {
if (sibling.getAttribute('data-selected') == 'true') {
resolve(asyncFunction(sibling));
}
})
resolve();
})
}
checkSiblings(siblings).then(asyncFunction(element));
我确定之前已经解决了这个问题,但我找不到合适的搜索键盘。
谢谢
如果只有一个兄弟姐妹符合条件,使用find
将简化您的代码:
const selected = [...siblings].find( elem => elem.getAttribute('data-selected') == 'true' );
将 checkSiblings
标记为 async
,因此它始终 return 是一个 Promise,并在适当的时候将其 return 设为 asyncFunction
Promise:
return selected ? asyncFunction(selected) : null;
然后你可以像以前一样将它们链接起来:
checkSiblings(siblings).then(() => asyncFunction(element));
加在一起你会得到这样的东西:
async function checkSiblings (siblings) {
const selected = [...siblings].find( elem => elem.getAttribute('data-selected') == 'true' );
return selected ? asyncFunction(selected) : null
}
checkSiblings(siblings).then(() => asyncFunction(element));
有几种方法。其中之一是使用 Array.reduce
到 resolve promises sequentially:
[...siblings].reduce(
async (prev, sibling)) => {
// Await initial/previous promise (discard results)
await prev;
// This condition may only be satisfied once
// (only one sibling may have data-selected true)
if (sibling.getAttribute('data-selected') == 'true') {
// Return the async function promise
return asyncFunction(sibling);
}
// async functions always returns a promise.
// No need to return anything
// Initial promise autoresolved
}, Promise.resolve())
// Once all have been executed
.then( () => asyncFunction(element));
在下面的代码中,当循环内的条件满足时,我们无法真正确定两个 asyncFunction 的调用顺序。
siblings.forEach(function(sibling, index) {
// This condition may only be satisfied once (only one sibling may have data-selected true)
if (sibling.getAttribute('data-selected') == 'true') {
asyncFunction(sibling);
}
})
asyncFunction(element);
因为我知道 asyncFunction() returns 一个 promise 我可以将它们链接起来以确保顺序:
asyncFunction(sibling).then(asyncFunction(element));
但是如何在考虑条件的情况下做到这一点?
我考虑过将循环包装在一个 promise 中,该 promise 在满足条件时或在循环结束后解析,但它似乎有点令人费解。
// Untested
function checkSiblings(siblings) {
let promise = new Promise(function(resolve, reject) {
siblings.forEach(function(sibling, index) {
if (sibling.getAttribute('data-selected') == 'true') {
resolve(asyncFunction(sibling));
}
})
resolve();
})
}
checkSiblings(siblings).then(asyncFunction(element));
我确定之前已经解决了这个问题,但我找不到合适的搜索键盘。
谢谢
如果只有一个兄弟姐妹符合条件,使用find
将简化您的代码:
const selected = [...siblings].find( elem => elem.getAttribute('data-selected') == 'true' );
将 checkSiblings
标记为 async
,因此它始终 return 是一个 Promise,并在适当的时候将其 return 设为 asyncFunction
Promise:
return selected ? asyncFunction(selected) : null;
然后你可以像以前一样将它们链接起来:
checkSiblings(siblings).then(() => asyncFunction(element));
加在一起你会得到这样的东西:
async function checkSiblings (siblings) {
const selected = [...siblings].find( elem => elem.getAttribute('data-selected') == 'true' );
return selected ? asyncFunction(selected) : null
}
checkSiblings(siblings).then(() => asyncFunction(element));
有几种方法。其中之一是使用 Array.reduce
到 resolve promises sequentially:
[...siblings].reduce(
async (prev, sibling)) => {
// Await initial/previous promise (discard results)
await prev;
// This condition may only be satisfied once
// (only one sibling may have data-selected true)
if (sibling.getAttribute('data-selected') == 'true') {
// Return the async function promise
return asyncFunction(sibling);
}
// async functions always returns a promise.
// No need to return anything
// Initial promise autoresolved
}, Promise.resolve())
// Once all have been executed
.then( () => asyncFunction(element));