英文:
Unhandled promises error inside array of promises
问题
我有这段代码。我发出一个writeRecords
请求,然后再次执行相同操作。
下一个请求我将其放入一个数组中,然后使用Promise.all()
。
我的问题是:
如果requests.push(writeClient.writeRecords(timestreamParams).promise())
出现错误,它会是一个未处理的Promise错误,还是try / catch
会捕获错误?
因为它在一个循环中,可能第一个数组元素已经发送了响应,而其他数据仍然在循环中,所以我不确定错误会发生在哪里?
let requests = []
const chunkSize = 100
for (let i = 0; i < Records.length; i += chunkSize) {
const chunk = Records.slice(i, i + chunkSize)
const timestreamParams = {
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}
await writeClient
.writeRecords(timestreamParams)
.promise()
.catch(() => {}) // 静默处理错误
// 成功重试相同的writeRecordsRequest,使用相同的记录和版本,因为writeRecords API是幂等的。
requests.push(writeClient.writeRecords(timestreamParams).promise())
}
try {
return Promise.all(requests).then((res) => ok(res))
} catch (error) {
return err({ error, params })
}
英文:
I have this piece of code. I make an writeRecords
request and then I do it again.
The next request I put in an array and use an Promise.all()
My question is:
What if requests.push(writeClient.writeRecords(timestreamParams).promise())
has an error, will it be an unhandled Promise error, or will the try / catch
catch the error?
Because it's in an loop it can be that the first element in the array has already sent back an response while the other data is still in the loop so I am not sure where the error will occur?
let requests = []
const chunkSize = 100
for (let i = 0; i < Records.length; i += chunkSize) {
const chunk = Records.slice(i, i + chunkSize)
const timestreamParams = {
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}
await writeClient
.writeRecords(timestreamParams)
.promise()
.catch(() => {}) // Silent error
// Successfully retry same writeRecordsRequest with same records and versions, because writeRecords API is idempotent.
requests.push(writeClient.writeRecords(timestreamParams).promise())
}
try {
return Promise.all(requests).then((res) => ok(res))
} catch (error) {
return err({ error, params })
}
答案1
得分: 1
是的,如果在达到Promise.all
之前(因为循环在await
上暂停)requests
数组中的一个promise被拒绝,你的代码可能会导致未处理的promise拒绝。如果循环以同步方式运行,就不会发生这种情况。
你应该使用以下两种方式之一:
并发版本:
try {
const requests = []
const chunkSize = 100
for (let i = 0; i < Records.length; i += chunkSize) {
const chunk = Records.slice(i, i + chunkSize)
const timestreamParams = {
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}
requests.push(writeClient.writeRecords(timestreamParams).promise())
}
const res = await Promise.all(requests)
ok(res)
} catch (error) {
return err({ error, params })
}
或者顺序版本:
try {
const res = []
const chunkSize = 100
for (let i = 0; i < Records.length; i += chunkSize) {
const chunk = Records.slice(i, i + chunkSize)
const timestreamParams = {
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}
res.push(await writeClient.writeRecords(timestreamParams).promise())
}
ok(res)
} catch (error) {
return err({ error, params })
}
但不要混合它们。如果你真的需要的话,.catch(() => {}) // Silence error
应该放在你不立即await
的promise上(也就是你放在数组中的那些promise)。
英文:
Yes, your code can lead to unhandled promise rejections, if one of the promises in the requests
array rejects before the Promise.all
is reached (due to the loop being suspended on the await
). It cannot happen if the loop were run synchronously.
You should be using either the concurrent version
try {
const requests = []
const chunkSize = 100
for (let i = 0; i < Records.length; i += chunkSize) {
const chunk = Records.slice(i, i + chunkSize)
const timestreamParams = {
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}
requests.push(writeClient.writeRecords(timestreamParams).promise())
}
const res = await Promise.all(requests)
ok(res)
} catch (error) {
return err({ error, params })
}
or the sequential version
try {
const res = []
const chunkSize = 100
for (let i = 0; i < Records.length; i += chunkSize) {
const chunk = Records.slice(i, i + chunkSize)
const timestreamParams = {
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}
res.push(await writeClient.writeRecords(timestreamParams).promise())
}
ok(res)
} catch (error) {
return err({ error, params })
}
but not the mix between them. If you really needed to, the .catch(() => {}) // Silence error
needs to go on the promise that you are not await
ing immediately (i.e. the ones you put in the array).
答案2
得分: 0
我会将重试逻辑放在一个单独的函数中,以便分离关注点。我的通常做法是将其添加到 Promise
中:Promise.retry
。
另外,您的请求彼此独立,因此可以并行执行它们。我们使用 Array::map()
来获得一个 Promise 数组。
async function retry(func, numberOfRetries = 1) {
let error;
do {
try {
return await func();
} catch (e) {
// 这里可以添加一些错误处理逻辑
error = e;
}
} while (--numberOfRetries);
throw error;
}
const chunkSize = 100;
const requests = Records.reduce((chunks, item, index) =>
((chunks[Math.floor(index / chunkSize)] ??= []).push(item)) && chunks
, [])
.map(chunk => retry(writeRecords({
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}).promise()));
try {
return Promise.all(requests).then((res) => ok(res))
} catch (error) {
return err({ error, params })
}
希望这可以帮助您。如果您有任何问题,请随时提出。
英文:
I would put the retry logic in a separate function to make some separation of concerns. My usual way is to add to the Promise
: Promise.retry
.
Also your requests are independent from each other so you could execute them in parallel. We use Array::map()
for that to get an array of promices
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
async function retry(func, numberOfRetries = 1) {
let error;
do {
try {
return await func();
} catch (e) {
// some error logic would be nice
error = e;
}
} while (--numberOfRetries);
throw error;
}
const chunkSize = 100;
const requests = Records.reduce((chunks, item, index) =>
((chunks[Math.floor(index / chunkSize)] ??= []).push(item)) && chunks
, [])
.map(chunk => retry(writeRecords({
DatabaseName: db_name,
TableName: TimeSpanRawE[table_name],
Records: chunk,
}).promise()));
try {
return Promise.all(requests).then((res) => ok(res))
} catch (error) {
return err({ error, params })
}
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论