首页 > 解决方案 > Firebase 实时数据库 - 多个顺序读取和写入操作,无需嵌套承诺

问题描述

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

为了在更新“注释”时更新用户的联系人数据,我需要执行一些顺序操作。我希望为“Note”中包含的每个“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)=>{})

我意识到嵌套承诺不是一件好事——因为我在执行 firebase 部署时收到警告。;)

328:9 警告避免嵌套承诺承诺/禁止嵌套
328:9 警告避免嵌套承诺承诺/禁止嵌套

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

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

标签: javascriptfirebasefirebase-realtime-databasepromisegoogle-cloud-functions

解决方案


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

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

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

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

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在可以正确处理错误的级别上,并且可以将.thens 链接在一起以避免重复.catches。

您还可以使用.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) => {
  // ...

推荐阅读