【问题标题】:How to avoid nesting promises with firebase transaction?如何避免使用firebase事务嵌套承诺?
【发布时间】:2020-03-19 11:12:06
【问题描述】:

在 onDelete 触发器中,我正在运行一个事务来更新某个对象。我现在需要在运行该事务之前进行一些清理并删除一些其他对象。添加清理代码后,我收到关于嵌套承诺的警告,我不知道如何摆脱。这是一个sn-p:

exports.onDeleteAccount = functions.firestore
.document('accounts/{accountID}')
.onDelete((account, context) => {
  // First do the cleanup and delete addresses of the account
  const query = admin.firestore().collection('account_addresses').where('accountID', '==', account.id);
  return query.get().then(addresses => {
    var promises = [];
    addresses.forEach(address=>{
      promises.push(address.ref.delete());
    })
    return Promise.all(promises);
  }).then(()=> {
    // Then run the transaction to update the account_type object
    return runTransaction(transaction => {
      // This code may get re-run multiple times if there are conflicts.
      const acc_type = account.data().type;
      const accountTypeRef = admin.firestore().doc("account_types/"+acc_type);
      return transaction.get(accountTypeRef).then(accTypeDoc => {
        // Do some stuff and update an object called users
        transaction.update(accountTypeRef, {users: users});
        return;          
      })
    })
  })
  .catch(error => {
    console.log("AccountType delete transaction failed. Error: "+error);
  });
})

【问题讨论】:

  • 你可以尝试使用await,但我不确定它是否完全支持(我不使用firebase)
  • 我觉得乍一看没有问题。
  • @appleapple 我在 transaction.get 行上收到警告以避免嵌套承诺。如果我删除了清理代码(query.get() 调用),那么这个警告就会消失......
  • @shaimo 我的意思是使用await没有问题,抱歉没有说清楚。
  • 哦,等等,runTransaction 会返回 Promise 吗?

标签: javascript node.js firebase google-cloud-firestore google-cloud-functions


【解决方案1】:

我认为问题不是来自Transaction,而是来自您调用delete()forEach 循环。您应该使用Promise.all() 来返回一个在传递给promises 数组的所有承诺(由delete() 返回)都已履行时履行的单一承诺,见下文。


另外,你做runTransaction(transaction => {...})runTransactionFirestore 的一个方法。你应该这样做admin.firestore().runTransaction(...)


因此,以下应该可以解决问题:

exports.onDeleteAccount = functions.firestore
    .document('accounts/{accountID}')
    .onDelete((account, context) => {
        // First do the cleanup and delete addresses of the account
        const query = admin.firestore().collection('account_addresses').where('accountID', '==', account.id);
        return query.get()
            .then(addresses => {
                const promises = [];
                addresses.forEach(address => {
                    promises.push(address.ref.delete());
                })
                return Promise.all(promises);
            }).then(() => {
                // Then run the transaction to update the account_type object
                return admin.firestore().runTransaction(transaction => {
                    // This code may get re-run multiple times if there are conflicts.
                    const acc_type = account.data().type;
                    const accountTypeRef = admin.firestore().doc("account_types/" + acc_type);
                    return transaction.get(accountTypeRef).then(accTypeDoc => {
                        // Do some stuff and update an object called users
                        transaction.update(accountTypeRef, { users: users }); 
                    })
                })
            })
            .catch(error => {
                console.log("AccountType delete transaction failed. Error: " + error);
            });
    })

【讨论】:

  • 你对 Promise.all 的需求是正确的(顺便说一句,我认为 promises 应该是 var,而不是 const),我相应地更改了我的代码(将在几秒钟内更新)。但它仍然没有删除带有“transaction.get”的承诺嵌套警告
  • 好的,让我看看。
  • 顺便说一句,仅供参考,const 数组中的值可以更改,它可以向 const 数组添加新项目,但不能引用新数组。
  • 您可以使用runTransaction(transaction => {}),但runTransactionFirestore 的方法。你应该这样做admin.firestore().runTransaction(...)
  • 是的,代码看起来不错,恕我直言。我认为这可能是您可以忽略的 TSLint 警告。
猜你喜欢
  • 1970-01-01
  • 2020-04-22
  • 2021-04-07
  • 2019-05-22
相关资源
最近更新 更多