【问题标题】:Cloud Functions: Avoid Nesting Promises for different conditions云函数:避免在不同条件下嵌套 Promise
【发布时间】:2023-03-15 09:37:01
【问题描述】:

我正在尝试编写一个函数,该函数在 Stores/{storeId}/{departmentId}/{productId} 被触发时考虑 3 个条件并在 ref.child('Home').child('Chiep').child(departmentId).child(productId) 中写入新数据。

1) 当firestore 中没有数据时,我需要填写Realtime DB 中的所有字段,方法是依次在firestore 的两个不同节点中查询:Stores 和Products拍摄他们的照片。

2) 当Stores 节点发生更改并且它来自同一个{storeId} 时,我只需要更新一些数据而无需进行任何其他查询。

3) 最后,当Stores 节点发生更改并且来自其他{storeId} 时,我只需要在Stores 节点中进行一次查询。

exports.homeChiepest = functions.firestore
.document('Stores/{storeId}/{departmentId}/{productId}')
.onWrite((change, context) => {

  const storeId = context.params.storeId;
  const departmentId = context.params.departmentId;
  const productId = context.params.productId;
  const ref = admin.database().ref();

  // Get an object with the current document value.
  // If the document does not exist, it has been deleted.
  const document = change.after.exists ? change.after.data() : null;

  // Get an object with the previous document value (for update or delete)
  const oldDocument = change.before.exists ? change.before.data() : null;

  // Prevent infinite loops
  if (!change.after.exists) {
    console.log('DATA DELETED RETURN NULL');
    return null;
  }

  const newPrice = document.price;
  const newTimestamp = document.timestamp;

  return ref.child('Home').child('Chiep')
  .child(departmentId).child(productId)
  .once('value')
  .then(dataSnapshot => {

    if (dataSnapshot.val() !== null) {

      console.log('CHIEP DOES exist');

      const oldPrice = dataSnapshot.val().price;
      const storeKey = dataSnapshot.val().storeKey;
      if (storeId === storeKey) {
        console.log('SAME STORE - Change price and timestamp');
        var newChiepest = {
          timestamp: newTimestamp,
          price: newPrice
        };
        return dataSnapshot.ref.update(newChiepest);

      } else {
        console.log('OTHER STORE - Verify if price is chieper...');
        if (newPrice <= oldPrice) {
          console.log('NEW PRICE: '+newPrice+' is chieper than the older one: '+oldPrice);

          return change.after.ref.parent.parent.get().then(doc => { // HERE Avoid nesting promises
            newStoreImg = doc.data().image;
            var newStoreChiep = {
              price: newPrice,
              storeImg: newStoreImg,
              storeKey: storeId,
              timestamp: newTimestamp
            };
            return dataSnapshot.ref.update(newStoreChiep);

          });

        } else {
          console.log('NEW PRICE: '+newPrice+' is mode EXPENSIVE than the older one: '+oldPrice);
        }
        return null;
      }

    } else {
      console.log('data does NOT exist, so WRITE IT!');

      let getStoreData = change.after.ref.parent.parent.get();
      let getProductData = admin.firestore().collection('Products').doc('Departments').collection(departmentId).doc(productId).get();

      return Promise.all([getStoreData, getProductData]).then(values => { // HERE Avoid nesting promises
        const [store, product] = values;
        var newHomeChiepest = {
          depId: departmentId,
          price: newPrice,
          prodImg: product.data().image,
          prodKey: productId,
          storeKey: storeId,
          storeImg: store.data().image,
          timestamp: newTimestamp
        };
        return dataSnapshot.ref.set(newHomeChiepest);

      });

    }


  })
  .catch(error => {
    console.log('Catch error reading Home: ',departmentId ,'/', productId,'; message: ',error);
    return false;
  });

});

问题是:查询或不查询另一个firestore节点的不同可能性导致我在上传Clound Function时出现警告,即:

警告避免嵌套promise promise/no-nesting

感谢您对重构此代码的任何帮助。

【问题讨论】:

  • 警告告诉你,像现在这样在另一个then 中使用then 被认为是糟糕的风格并且容易出错。你可以重写它。 stackoverflow.com/questions/49844854/…
  • 停止嵌套 promise 的最简单方法是使用 async/await
  • 我同意。我见过的最相似的问题在这里:stackoverflow.com/q/55901953/4300670,但它没有在 IF 语句中查询其他firebase 节点。所以我被卡住了。

标签: javascript firebase promise google-cloud-functions


【解决方案1】:

您可以使用变量来管理“分流”,具体取决于不同的情况,如下(未经测试):

exports.homeChiepest = functions.firestore
    .document('Stores/{storeId}/{departmentId}/{productId}')
    .onWrite((change, context) => {

        const storeId = context.params.storeId;
        const departmentId = context.params.departmentId;
        const productId = context.params.productId;
        const ref = admin.database().ref();

        const document = change.after.exists ? change.after.data() : null;

        // Prevent infinite loops
        if (!change.after.exists) {
            console.log('DATA DELETED RETURN NULL');
            return null;
        }

        const newPrice = document.price;
        const newTimestamp = document.timestamp;

        let shunting;   // <-- We manage the shunting through this variable
        let chiepRef;

        return ref.child('Home').child('Chiep')
            .child(departmentId).child(productId)
            .once('value')
            .then(dataSnapshot => {

                chiepRef = dataSnapshot.ref;

                if (dataSnapshot.val() !== null) {

                    console.log('CHIEP DOES exist');

                    const oldPrice = dataSnapshot.val().price;
                    const storeKey = dataSnapshot.val().storeKey;
                    if (storeId === storeKey) {
                        shunting = 1
                        console.log('SAME STORE - Change price and timestamp');
                        var newChiepest = {
                            timestamp: newTimestamp,
                            price: newPrice
                        };
                        return chiepRef.update(newChiepest);

                    } else {
                        console.log('OTHER STORE - Verify if price is chieper...');
                        if (newPrice <= oldPrice) {
                            console.log('NEW PRICE: ' + newPrice + ' is chieper than the older one: ' + oldPrice);
                            shunting = 2

                            return change.after.ref.parent.parent.get();

                        } else {
                            console.log('NEW PRICE: ' + newPrice + ' is mode EXPENSIVE than the older one: ' + oldPrice);
                            shunting = 3
                            return null;
                        }

                    }

                } else {
                    console.log('data does NOT exist, so WRITE IT!');
                    shunting = 4;
                    let getStoreData = change.after.ref.parent.parent.get();
                    let getProductData = admin.firestore().collection('Products').doc('Departments').collection(departmentId).doc(productId).get();

                    return Promise.all([getStoreData, getProductData])

                }


            })
            .then(result => {

                if (shunting === 2) {
                    const newStoreImg = result.data().image;
                    var newStoreChiep = {
                        price: newPrice,
                        storeImg: newStoreImg,
                        storeKey: storeId,
                        timestamp: newTimestamp
                    };
                    return chiepRef.update(newStoreChiep);
                } else if (shunting === 4) {
                    const [store, product] = result;
                    const newHomeChiepest = {
                        depId: departmentId,
                        price: newPrice,
                        prodImg: product.data().image,
                        prodKey: productId,
                        storeKey: storeId,
                        storeImg: store.data().image,
                        timestamp: newTimestamp
                    };
                    return chiepRef.set(newHomeChiepest);
                } else {
                    return null;
                }

            })
            .catch(error => {
                console.log('may be adapted, function of shunting', error);
                return null;
            });

    });

【讨论】:

  • ReferenceError: dataSnapshot is not defined for return dataSnapshot.ref.set(newHomeChiepest);
  • let chiepRef; return ref.child('Home').child('Chiep').child(departmentId).child(productId.once('value').then(dataSnapshot =&gt; {chiepRef = dataSnapshot.ref;...})....
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 2018-11-13
  • 2020-08-24
  • 2018-06-18
  • 1970-01-01
相关资源
最近更新 更多