我正在尝试执行以下操作:
command.permissions.some(async permissionsKey => {
switch (permissionsKey) {
case "all": {
return true;
}
case "OWNER": {
return await msg.roomContext.isRoomOwnerId(msg.getStaticUserUID());
}
default: {
return config.users_groups[permissionsKey].includes(msg.getStaticUserUID());
}
}
});
但是它始终是正确的,因为Array.prototype.some不期望异步函数,因此在调用该函数时会返回一个promise。一个承诺是真实的。
我想知道将异步函数与Array.prototype函数(特别是some函数)一起使用的最佳途径。
答案 0 :(得分:3)
如果您希望在第一个承诺以true
解决后立即获得结果,您也可以这样做:
const somePromise = promises =>
new Promise((resolve, reject) => {
let resolveCount = 0;
const resolved = value => {
if (value) {
resolve(true);
} else if (++resolveCount === promises.length) {
resolve(false);
}
};
for (const promise of promises) {
promise.then(resolved, reject);
}
});
其他花哨的方法:
const never = new Promise(() => {});
const somePromise = promises => Promise.race([
Promise.race(promises.map(async p => !!await p || never)),
Promise.all(promises).then(r => r.some(Boolean)),
]);
但是,在您的特定情况下,由于最多只有一个承诺,因此有更好的方法来实现:
let hasPermission =
command.permissions.some(permissionsKey => {
switch (permissionsKey) {
case "all":
return true;
case "OWNER":
return false;
default:
return config.users_groups[permissionsKey].includes(msg.getStaticUserUID());
}
});
if (!hasPermission && command.permissions.includes("OWNER")) {
hasPermission = await msg.roomContext.isRoomOwnerId(msg.getStaticUserUID());
}
答案 1 :(得分:2)
首先将数组转换为Promises数组,然后在其上调用Promise.all
,并检查结果数组的.some
是否真实。如果愿意,您可以通过检查Promise数组中的.some
是否为真非Promise来避免等待整个Promise数组解决。
cpermisPromises = command.permissions.map(permissionsKey => {
switch (permissionsKey) {
case "all":
{
return true;
}
case "OWNER":
{
return msg.roomContext.isRoomOwnerId(msg.getStaticUserUID());
}
default:
{
return config.users_groups[permissionsKey].includes(msg.getStaticUserUID());
}
}
});
if (cpermisPromises.some(result => result && typeof result.then !== 'function')) {
// at least one was truthy, don't need to wait for async call to complete
} else {
Promise.all(cpermisPromises).then((results) => {
if (results.some(result => result)) {
// at least one was truthy
}
});
}
Promise.all
可以接受包含 any 值的数组,但是将在Promise.all
解析之前等待所有Promise值解析。
这是一个替代方法,它使您可以在运行Promises之前检查任何同步值是否真实:
let found = false;
const promFns = [];
forloop:
for (let i = 0; i < command.permissions.length; i++) {
const permissionsKey = command.permissions[i];
switch (permissionsKey) {
case "all":
found = true;
break forloop;
case "OWNER":
proms.push(() => msg.roomContext.isRoomOwnerId(msg.getStaticUserUID()));
break;
default:
if (config.users_groups[permissionsKey].includes(msg.getStaticUserUID())) {
found = true;
break forloop;
}
}
}
if (found) {
// done, at least one truthy value was found synchronously
} else {
// need to run promises
Promise.all(
promFns.map(fn => fn())
)
.then((results) => {
if (results.some(result => result)) {
// done, at least one truthy value was found asynchronously
} else {
// no truthy value was found
}
});
}
或者,如果要连续发送请求,这可能会导致总体上减少请求,但需要更长的时间才能完成,请将Promise.all
替换为:
let foundProm = false;
for (const fn of promFns) {
if (await fn()) {
foundProm = true;
break;
}
}
if (foundProm) {
// done, at least one truthy value was found synchronously
}else {
// no truthy value was found
}
答案 2 :(得分:1)
我来这里是为了寻找类似的用途,然后发现这篇很棒的文章介绍了这个手册 asyncSome 函数: https://advancedweb.hu/how-to-use-async-functions-with-array-some-and-every-in-javascript/
当谓词返回真值时,它也会中断循环:
const arr = [1, 2, 3];
const asyncSome = async (arr, predicate) => {
for (let e of arr) {
if (await predicate(e)) return true;
}
return false;
};
// Example of use for this function:
const res = await asyncSome(arr, async (i) => {
console.log(`Checking ${i}`);
await sleep(10);
return i % 2 === 0;
});
应用于此用例,它只是:
asyncSome(command.permissions, async permissionsKey => {
switch (permissionsKey) {
case "all": {
return true;
}
case "OWNER": {
return await msg.roomContext.isRoomOwnerId(msg.getStaticUserUID());
}
default: {
return config.users_groups[permissionsKey].includes(msg.getStaticUserUID());
}
}
});
就像 OP 建议的方式一样简单。