如何解决在筛选操作中使用async / await,在第一次等待调用后不等待完成
对于特定功能,需要数据库中的标签列表(rfids),但应检查各种表。
问题集中在长期运行的问题上,没有await
在继续进行下一步之前就结束。
问题:
下面调用的代码如下运行(#号与下面代码中的数字相对应):
-
getAllTags()
被调用,启动proc -
await db.dbRfid.findAll()
返回X数量的有效结果(不是Promise
个对象) - 开始过滤有效对象上的调用并等待完成(因为内部的某些函数调用是异步调用,所以请等待。
- 致电
const driverTags = await tag.getDrivers();
在这一点上,人们希望该函数返回结果并继续执行下一个函数,即
// #5
const truckTags = await tag.getTrucks();
对于每个allTags
项目,实际上发生了什么,getDrivers()
被调用,filter()
退出,代码继续执行下一个:
// #6
if (pureTags) {
return filteredTags;
}
问题:
据我了解,我正在await
正确进行async
个操作,但似乎该过滤器仅接受/允许一个async
操作。
我认为我做错了什么,但我无法确定问题的原因。任何建议将不胜感激!
下面的完整代码实现:
以
表示const listOfTags = await getAllTags();
特定标签要求(所有有效,未使用,已启用和未吊销的标签)
const listOfTags = await getAllTags(false,true,true);
问题代码:
// #1
const getAllTags = async (pureTags = false,unused = true,enabled = true,notRevoked = false) => {
// #2
let allTags = await db.dbRfid.findAll()
// #3
let filteredTags = await allTags.filter(async tag => {
// check tag used
if (unused) {
// #4
const driverTags = await tag.getDrivers();
// #5
const truckTags = await tag.getTrucks();
const userTags = await tag.getUsers();
if (driverTags.length > 0) {
return false;
}
if (truckTags.length > 0) {
return false;
}
if (userTags.length > 0) {
return false;
}
}
// check tag enabled
if (enabled && !tag.enabled) {
return false;
}
// check tag revoked or return true
return notRevoked && !tag.revoked;
});
// return tags as is
// #6
if (pureTags) {
return filteredTags;
}
return filteredTags.map(tag => {
return {
id: tag.id,rfid: tag.rfid,expiryDate: tag.expiryDate,revoked: tag.revoked,enabled: tag.enabled
}
});
}
更新
我应该提到:
- 未显示任何类型的“错误”以表明存在某些问题。
-
.getDrivers()
是sequelize创建的获取方法,它返回承诺。
更新2
由evgeni fotia
发表评论
本来我有这段代码,但是选择不包含它,因为它可能会使事情变得复杂。但是,这是我尝试添加await Promise.all()
的原始代码。
const getAllTags = async (pureTags = false,notRevoked = false) => {
let allTags = await db.dbRfid.findAll()
let filteredTags = await Promise.all(
// await allTags.filter(async tag => { //tried the await here too - for good measure
allTags.filter(async tag => {
// check tag used
if (unused) {
const driverTags = await tag.getDrivers();
const truckTags = await tag.getTrucks();
const userTags = await tag.getUsers();
if (driverTags.length > 0) {
return false;
}
if (truckTags.length > 0) {
return false;
}
if (userTags.length > 0) {
return false;
}
}
// check tag enabled
if (enabled && !tag.enabled) {
return false;
}
// check tag revoked or return true
return notRevoked && !tag.revoked;
})
);
// return tags as is
if (pureTags) {
return filteredTags;
}
return filteredTags.map(tag => {
return {
id: tag.id,enabled: tag.enabled
}
});
}
请注意,在此更新或原始问题中运行代码后,我看到调试器敲击getDrivers()
方法,然后(HTTP)响应仅在0.5〜1s之后发送到客户端我看到getDrivers()
方法正在返回并继续执行下一个方法。
解决方法
您的中心问题是T.J.乔德(Chowder)评论说,您正在尝试.filter()
有时是布尔值,有时是诺言的内容。
您应该以不同的步骤进行映射和过滤。我倾向于使用.then()
语法,所以这是我的方法:
const getAllTags = (pureTags = false,unused = true,enabled = true,notRevoked = false) => {
return db.dbRfid.findAll()
.then(allTags => allTags.map(tag => Promise.resolve(
enabled === tag.enabled && notRevoked === !tag.revoked && Promise.all([
tag.getDrivers(),tag.getTrucks(),tag.getUsers()
]).then(results => results.some(r => r.length))
).then(ok => ok ? tag : null)))
.then(pendingTags => Promise.all(pendingTags))
.then(resolvedTags => resolvedTags.filter(tag => tag))
.then(filteredTags => filteredTags.map(tag => pureTags ? tag : {
id: tag.id,rfid: tag.rfid,expiryDate: tag.expiryDate,revoked: tag.revoked,enabled: tag.enabled
}));
};
此代码的逻辑:
- 从数据库中获取标签
产生Promise<Tag[]>
,即对一组标签的承诺 - 根据我们使用
null
得出的条件,将每个标签映射到一个新的Promise,该Prom可以解析为标签本身或Promise.resolve()
,以解决潜在的(*) 该支票的异步性质
产生Promise<Promise<Tag|null>[]>
- 等待所有内在的诺言使用
Promise.all()
来解决
产生<Promise<(Tag|null)[]>
- 过滤掉
null
值(即我们不需要的标签)
产生<Promise<Tag[]>
- 将标签映射到所需的整体结果数据结构,具体取决于
pureTags
产生<Promise<(Tag|object)[]>
(*)Promise.all()
仅在先决条件因短路而退房时调用。如果不是,那么它只是一个Promise.resolve(false)
,它将立即解析为false
。在另一种情况下,它将是Promise.resolve(<Promise<Boolean>)
,其工作方式与Promise.resolve(Boolean)
完全相同。这样我们就可以统一同步测试和异步测试。
在随后的.then()
中,我们可以决定是否返回tag
-或null
,以指示此标记未通过过滤条件。然后,null
选取resolvedTags.filter(tag => tag)
的值。
请注意,您的代码会序列化三个异步检查(getDrivers
,getTrucks
,getUsers
),因为等待每个异步检查之后才能开始下一个检查。使用Promise.all()
可以使它们并行运行,这就是为什么我不喜欢对所有内容都使用async
/ await
的原因之一。
我保留将其重写为async
/ await
样式作为练习。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。