有办法将.then承诺添加到for循环中吗?

huangapple go评论65阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年5月11日 16:05:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76225380.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定