Firebase实时数据库-多个顺序的获取和写入操作,而无需嵌套承诺

时间:2019-09-06 09:28:36

标签: javascript firebase firebase-realtime-database promise google-cloud-functions

我正在使用Firebase Realtime数据库进行存储。

为了在更新“注释”时为用户更新联系人数据,我需要执行一些顺序操作。我希望为“注释”中包含的每个“ affectedUser”更新/推送联系人节点。

下面是我的数据库的粗略表示。

-notes
  -note123456 <-- Note being updated
    affectedUsers: {'L1234567890ABC': true, 'L0987654321XYZ': true} <-- affectedUsers
-users <-- Compose contact objects from here for all affectedUsers
  -L1234567890ABC
    name
    alias
    email
    avatar
    favouriteColour
  -L0987654321XYZ
-contacts <-- Add new contacts here
  -L1234567890ABC 
    -ABCDEFGHIJKLMNO0123 <-- Already added contact
      alias
      name
  -L0987654321XYZ
    -ABCDEFGHIJKLMNO0123 <-- Already added contact

我的出发点是需要更新的“ affectedUsers”列表-用户ID列表。

所需的,简化的工作流程如下所示

  1. 迭代“ affectedUsers”并撰写“联系卡”
  2. 然后迭代所有“ affectedUsers”并将联系人卡片添加到每个受影响的用户中

我当前的代码

const dbRoot = snapshot.ref
affectedUsers = ['-L1234567890ABC', '-L0987654321XYZ']
let promises = [];

affectedUsers.forEach((affectedUser) => {
  const ref = dbRoot.child(`users/${affectedUser}`)
  promises.push(
    ref.once('value', (userSnapshot)=>{
      const userNodeData = userSnapshot.val()
      const contactObject = {
        alias: userNodeData.alias,
        name: userNodeData.name
      }
    return contactObject
  );
})

Promise.all(promises).then((contactObjects) => {
  let updateContactsPromises = [] //Collect second promise chain
  //Check contacts of affectedUsers
  affectedUsers.forEach((userId) => {
    const ref = dbRoot.child(`contacts/${userId}`)
    updateContactsPromises.push(
      ref.once('value', (updateUserContactsSnapshots) => {
        updateUserContactsNodeData = updateUserContactsSnapshots.val()
        //Remove userId from additions, prepare database update object, push data
        //...
      })
    )
  })

  //Execute second, and last promise chain
  Promise.all(updateContactsPromises) //Line 328
  .then(()=>{
    //...
  })
  .catch((err)=>{})
})
.then(()=>{
  //...
})
.catch((err)=>{})

我意识到嵌套的Promise不是一件好事-因为执行Firebase部署时会收到警告。 ;)

  

328:9警告避免嵌套promises promise / no-nesting
  328:9   警告避免嵌套promises promise / no-nesting

     

✖2个问题(0个错误,2个警告)

如何确保我的调用按顺序执行而没有嵌套承诺?

1 个答案:

答案 0 :(得分:1)

问题是当您直接在另一个.then内有一个.then时。通常,可以通过返回下一个Promise来解决此问题,而不是先嵌套。例如,更改

prom.then(() => {
  getAnotherProm().then(handleOther);
});

prom.then(() => {
  return getAnotherProm()
})
.then(handleOther);

在这里,您可以返回第二个Promise.all以避免嵌套.then

Promise.all(promises)
  .then((contactObjects) => {
    let updateContactsPromises = [] //Collect second promise chain
    //Check contacts of affectedUsers
    affectedUsers.forEach((userId) => {
      // ...
    })

    //Execute second, and last promise chain
    return Promise.all(updateContactsPromises)
  })
  .then((updateContactsValues) => {
    // handle resolve value of updateContactsPromises
  })
  .catch((err) => {
    // handle errors
  })

在一个可以正确地处理错误的级别上记住仅.catch,并且可以将.then链接在一起以避免避免重复.catch es。

您还可以使用.map代替.forEach一次构造所有Promises数组,例如:

const dbRoot = snapshot.ref
affectedUsers = ['-L1234567890ABC', '-L0987654321XYZ']
const affectedUserPromises = affectedUsers.map((affectedUser) => {
  const ref = dbRoot.child(`users/${affectedUser}`)
  return ref.once('value', (userSnapshot) => {
    const userNodeData = userSnapshot.val()
    return {
      alias: userNodeData.alias,
      name: userNodeData.name
    };
  });
});
Promise.all(affectedUserPromises).then((contactObjects) => {
  // ...