英文:
Is there a way to add a .then promise to a for Loop?
问题
I am working on a Firebase cloud function to update a field value for every element of the array I provide.
Below is my loop.
I would like for it to add a document to another collection as soon as this loop has been completed.
// FOR EACH ITEM
sortedArray.forEach(([key, val]) => {
walletRef.doc('j10wmCUhUWPxYJpIElBxmFAEI6l1').update({
[val.product]: admin.firestore.FieldValue.increment(val.quantity),
})
})
When I try to add a .then like below, it fails
// FOR EACH ITEM
sortedArray.forEach(([key, val]) => {
walletRef.doc('document_id_here').update({
[val.product]: admin.firestore.FieldValue.increment(val.quantity),
})
}).then((doc) => {
logsRef.add({
user_id: "document_id_here",
product: items,
transactionType: "purchase",
date: new Date(),
})
});
Logged error:
textPayload: "Function execution took 2594 ms, finished with status: 'crash'"
The field values are updated but the new document is not created.
Please help.
Thanks.
英文:
I am working on a Firebase cloud function to update a field value for every element of the array I provide.
Below is my loop.
I would like for it to add a document to another collection as soon as this loop has been completed.
// FOR EACH ITEM
sortedArray.forEach(([key, val]) => {
walletRef.doc('j10wmCUhUWPxYJpIElBxmFAEI6l1').update({
[val.product]: admin.firestore.FieldValue.increment(val.quantity),
})
})
When I try to add a .then like below, it fails
// FOR EACH ITEM
sortedArray.forEach(([key, val]) => {
walletRef.doc('document_id_here').update({
[val.product]: admin.firestore.FieldValue.increment(val.quantity),
})
}).then((doc) => {
logsRef.add({
user_id: "document_id_here",
product: items,
transactionType: "purchase",
date: new Date(),
})
});
Logged error:
textPayload: "Function execution took 2594 ms, finished with status: 'crash'"
The field values are updated but the new document is not created.
Please help.
Thanks.
答案1
得分: 2
Your update loop seems unnecessary since you're performing the operations on the same document.
Try something like this instead, setting multiple properties at once:
walletRef
.doc("document_id_here")
.update(
Object.fromEntries(
sortedArray.map(({ product, quantity }) => [
product,
admin.firestore.FieldValue.increment(quantity),
])
)
)
.then((writeResult) => {
// ...
});
From the docs for "Increment a numeric value"...
★ Note: If the field does not exist or if the current field value is not a numeric value, the operation sets the field to the given value.
英文:
Your update loop seems unnecessary since you're performing the operations on the same document.
Try something like this instead, setting multiple properties at once
walletRef
.doc("document_id_here")
.update(
Object.fromEntries(
sortedArray.map(({ product, quantity }) => [
product,
admin.firestore.FieldValue.increment(quantity),
])
)
)
.then((writeResult) => {
// ...
});
From the docs for Increment a numeric value...
> ★ Note: If the field does not exist or if the current field value is not a numeric value, the operation sets the field to the given value
答案2
得分: 2
根据您的要求,以下是翻译好的部分:
根据您的需求,有不同的方法来使用Promise进行循环处理。
第一种方法是使用Promise.all
和.map
:
Promise.all(
sortedArray.map(item => {
return 进行返回Promise的操作()
.then(同时返回Promise的效果);
})
).then(在所有Promise都解析后执行的操作);
在所有Promise都解析后执行的操作将收到一个包含已解析Promise中返回的值的数组。
从文档中得知:
Promise.all() 静态方法接受一个Promise的可迭代对象作为输入,并返回一个单一的Promise。当输入的所有Promise都成功解析时(包括传递空的可迭代对象时),此返回的Promise会成功解析,并包含解析值的数组。当输入的Promise中任何一个拒绝时,它会拒绝,并返回第一个拒绝原因。
需要注意的是:Promise.all
将同时运行所有的Promise,所以如果有1000个异步http请求,可能会面临速率限制。
为了避免速率限制,您可以使用for await
的顺序方式:
(async () => {
const results = [];
for (const item of sortedArray){
const result1 = await 进行返回Promise的操作();
results.append(await effect_that_also_return_promise(result1));
}
await 在所有Promise都解析后执行的操作(results)
})().then(afterAbsolutelyAllPromisesResolved);
区别在于Promise将如何被解析。在Promise.all方法中,您的Promise将以“并发”方式运行。在for await方法中,Promise将按顺序解析。
英文:
Depending on your requiremenents there are different ways to loop with promises
The first one is to use Promise.all
and .map
:
Promise.all(
sortedArray.map(item => {
return do_something_that_returns_promise()
.then(effect_that_also_return_promise);
})
).then(afterAllPromisesResolved);
afterAllPromisesResolved - will receive an array of values that are returned resolved in promises.
From docs:
> The Promise.all() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when all of the input's promises fulfill (including when an empty iterable is passed), with an array of the fulfillment values. It rejects when any of the input's promises rejects, with this first rejection reason.
Important to note: Promise.all
will run promises all together at the same time, so if you have 1000 async http request it may face ratelimits
To avoid rate limits you can use sequential way with for await:
(async ()=> {
const results = [];
for (const item of sortedArray){
const result1 = await do_something_that_returns_promise();
results.append(await effect_that_also_return_promise(result1));
}
await afterAllPromisesResolved(results)
})().then(afterAbsolutelyAllPromisesResolved);
The difference is in the way the promises will be resolved. In Promise.all approach your promises will run in "concurrent" way. In for await approach the promises will be resolved in sequential fashion
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论