如何确保所有promise都得到正确解决?在这里,即使在函数执行之后,一些语句仍然会被打印出来(我添加了注解的语句)。我觉得getAllRecords没有正确地完成promise。我哪里做错了?
const getAllRecords = async (offset = 0) => {
return fetchRecord(offset, 10).then((resp) => {
console.log("Called fetchRecord")
if (resp.status === 'success') {
let responseData = resp.data
if (responseData.length === 0 {
return ({ status: 'success' })
}
return proccessData(responseData).then((updateResp) => {
if (updateResp.status === 'success') {
offset += 10
return getAllRecords(offset)
} else {
return ({ status: 'error' })
}
}).catch(err => {
return ({ status: 'error' })
})
} else {
return ({ status: 'error' })
}
}).catch(err => {
return ({ status: 'error' })
})
}
const mainFunc = async () => {
console.log('Inside mainFunc')
return new Promise((resolve, reject) => {
return firestore.getAllCities()
.then(async (cities) => {
return getAllRecords().then(getAllRecordsResponse => {
console.log("Called getAllRecords") //
if (getAllRecordsResponse.status === 'success') {
return getAllRecordsResponse
} else {
return reject({ status: 'error' })
}
}).then((getAllRecordsResponse) => {
let updateArray = []
console.log("Updating firestore db")
for (const city of cities) {
updateArray.push(firebaseDao.updatecityDoc(city))
}
return Promise.allSettled(updateArray).then((responseArr) => {
let errorArr = []
responseArr.map((item) =>
item.status === 'rejected' ? errorArr.push(item.reason) : null
)
if (!errorArr.length > 0) {
console.log("done processing") //
return resolve({ status: 'success' })
} else {
return resolve({ status: 'error' })
}
})
}).catch((err) => {
return resolve({ status: 'error' })
})
}).catch((err) => {
return resolve({ status: 'error' })
})
})
}
字符串
我试图从fetchRecord中的其他地方获取记录,并在processData中处理提取的数据。getAllRecords是一个递归,因为我们不能一次获取所有数据,只能提取10条记录,所以我提取记录,直到我得到一个空的响应。
我不确定的是,承诺在哪里没有得到适当的处理。我是不是漏掉了什么?
有没有一种方法可以只使用promise而不是async/await?
3条答案
按热度按时间lnlaulya1#
下面是imo的一个实现,它达到了同样的目的,但有更好的实践,并解决了你的un
await
艾德promise的问题!请注意,我欺骗了您引用但未包含在问题中的所有函数,因此您可以实际运行此代码:字符串
一些做法,使这段代码,海事组织,更好:
{ status: 'failed' }
的东西!这将使你的代码更精简、健壮、更容易调试!function*
)用于执行重复批次选择.then
使代码变得不那么不可维护,我就删除了它await
艾德promise这种新格式提出了一个问题:为什么
getAllRecords
返回的记录被忽略?这不可能是正确的--他们不应该考虑firebaseDoc.updatecityDoc(...)
吗?sq1bmfud2#
TL;DR
**不要嵌套异步代码。**这是避免大多数错误的经验法则。
完整版本:
通常情况下,您希望根据另一个异步操作的结果执行一些异步操作,然后执行其他操作。有两种正确的方法,也有很多错误的方法。假设我们有两个Promise返回函数
f
和g
,我们需要将f
的结果传递给g
。错了
嵌套
.then
处理程序,如示例代码所示:字符串
为什么不好
假设不是2步而是10步,每一步都取决于前面的结果。现在,在你得到真正有用的代码之前,你可能会有40个空格的缩进,并且你已经重新创建了可怕的callback hell Promises,它应该保护我们免受所有 Package 器和额外分配带来的更差性能的影响。还有错误处理呢?你只能在单个Promise级别执行
.catch
,链中的每个.then
都是潜在的UnhandledRejectionError。错了
混合
.then
和async/await
:型
为什么不好
与将
doTheThing
标记为async
并使用await
首先获得调用f
的结果相比,这显然是次优的。错了
当内部Promise解析时,解析外部Promise。假设我们想从
doTheThing
* 返回 * 一个gResult
的Promise:型
为什么不好
这就是传说中的Promise constructor anti-pattern,除了Q&A中列出的问题之外,您不能再将错误处理推迟到调用者。
对
型
如果你需要做更多的中间工作,而不仅仅是调用
g
并得到f
的结果,你可以这样做:型
这利用了Promises的自动扁平化:当我们从
.then
返回一个Promise时,我们得到的是Promise<T>
而不是Promise<Promise<T>>
。我们甚至可以添加另一个.then
:型
这种方法的另一个好处是,最后的单个
.catch
将捕获.then
s链中任何地方的 * 所有 * Promise拒绝,如果您嵌套调用而不是链接它们,您不能这样做!也对
型
很简单。完成任务。可以与
try/catch
结合使用,以轻松处理错误:型
有关这些原则应用于代码的想法,请参阅this other answer that refactored your code。
pqwbnv8z3#
这有点难以发现,但问题的根源是use of the
Promise
constructor antipattern。当你试图处理所有的错误时,你犯了这样的错误字符串
完成
mainFunc
。但它并没有-它只从当前的.then()
处理程序返回undefined
,然后它以undefined
作为参数执行下一个.then()
处理程序,即使在你的promise已经被拒绝后也继续执行。您可以通过在这里不链接
.then(…).then(…)
来修复错误,而是使用单个函数:型
但是,这并不能大大改善您的代码。您的错误处理到处都是,有很多重复的代码,您应该摆脱
new Promise
。另外,如果你想使用.then()
而不是await
,没有理由将你的函数声明为async
。对于错误处理,将错误保留为拒绝,并且只在最后将它们处理并转换为结果对象。
型
虽然这段代码已经简单得多了,但我建议使用
async
/await
语法,如其他两个答案所示。您不再需要对getAllRecords
使用递归,也不会有那么多嵌套,这大大简化了重构。