Firebase交易,您必须返回承诺

时间:2018-09-28 15:16:06

标签: typescript firebase promise transactions angular6

我正在尝试弄清楚如何从angular 6 /打字稿应用程序将事务写入Firebase数据库。

我用作指导的一个工作示例如下:

const transactions = [];

return db.runTransaction(function(transaction) {
            // const promises = [];
            descriptionsInDB.forEach(dbDescription => {
                if (dbDescription.matched === false) {
                    // item wasn't found, so add the item to the transaction.
                    const phraseItem: PhrasesDB = {
                        query: dbDescription.description,
                        updatedAt: Date.now(),
                        createdAt: Date.now(),
                        workflows: {
                            [workflowId]: true
                        }
                    };
                    const newPhrasesRef = phrasesCol.doc();
                    transactions.push(transaction.set(newPhrasesRef, phraseItem));
                } else {
                    if (dbDescription.data.workflows && dbDescription.data.workflows[workflowId]) {
                        // do nothing, this phrase is already part of the record.
                    } else { // update the workflows that are part of the record.
                        const workflows = { 
                            workflows: {
                                [workflowId]: true
                            }
                         };
                        const phrasesRef = phrasesCol.doc(dbDescription.dbId);
                        transactions.push(transaction.update(phrasesRef, workflows));
                    }
                }
            });

            return Promise.all(transactions); 
        })

我确定的关键要素如下:

1)创建一个数组来保存您的交易:const transaction = [];

2)开始事务:返回db.runTransactions(function(transaction){…

3)使用以下事务执行数据库查询:transaction.set(newPhraseRef,statementItem);

4)将查询返回的事务推送到事务数组:transactions.push(transaction.set(newPhraseRef,statementItem));

5)用交易数组返回一个承诺:return Promise.all(transaction);

如果我拥有这项权利,那么我应该可以将此公式应用于我要编写的交易,并且应该可以运行:

        const pendingRef = `Pending/${req.query.inviteId}`;
        const acceptance = {
          'cryptoInvitationAcceptance': req.body.cryptoInvitationAcceptance,
          'reason': (req.body.reason !== undefined ? req.body.reason : '')
        }
return db.runTransaction(function(t) {
          const transArray = [];
          const docRef = db.collection('Pending').doc(req.query.inviteId);
          transArray.push(t.set(docRef, acceptance));
          return Promise.all(transArray);
        }).then(result => {
          console.log('result = ', result);
        }).catch(err => {
          console.log('err = ', err);
        });

但是它总是转到catch块并打印出消息:

err =错误:您必须在transaction()回调中返回Promise。

但是我正在兑现诺言,不是吗?这行代码:return Promise.all(transArray)是我要返回的承诺。不?

2 个答案:

答案 0 :(得分:0)

请阅读Transaction set()的文档-它不返回承诺。这可能会使Firestore SDK感到困惑,因为您将返回Promise.all()一系列不是承诺的东西。因此,也许它认为您返回了错误。

您可能根本不需要从事务处理程序函数中返回任何内容。只需调用set()即可完成。如果您想通过返回的承诺pass that value out to the caller of runTransaction,只需从事务处理程序中返回一些东西。

顺便说一句,在您的第一个示例中,您不应该将promise收集到在处理函数之外定义的数组中。如果事务处理程序多次运行,可能会导致问题。正如我链接的文档所述:

  

请勿在事务功能内部修改应用程序状态。   这样做会引入并发问题,因为交易   函数可以运行多次,并且不能保证在   用户界面线程。

事务外的数组将被视为“应用程序状态”,因为它不在函数本身内部。

答案 1 :(得分:0)

事实证明,这是最好的方法:

      return t.get(pendingDocRef).then(data => {
        t.set(pendingDocRef, acceptance, {merge:true});
      });

get(...)返回所要的承诺,因此set(...)不必这样做。

我不喜欢这样。我仍然认为我应该能够自行完成交易中的交易(即无交易)。

我还发现,这类 有用:

return t.set(...).commit();

commit()还返回一个promise,但是然后我得到了一个奇怪的行为:事务一遍又一遍地重复,直到它进入catch块,并出现“事务已过期”错误。尽管如此,数据仍会提交到数据库,因此,如果您不介意错误(只是让它通过),则commit()也会起作用。

有关详情,请参见此帖子:firebase transaction repeating when committing