【问题标题】:HTML: How to get a calculation result before executing a functionHTML:如何在执行函数之前获取计算结果
【发布时间】:2021-02-16 07:01:41
【问题描述】:

我有一个要执行的脚本。我需要脚本,按下提交按钮:

  1. 从 Google Firestore 中获取值
  2. 在计算中使用这些值
  3. 使用此计算的结果写回 Firestore 数据库

我已将console.log("eff[1,2,3]" + result of calculation) 用于帮助在控制台日志中跟踪执行顺序。它首先显示eff3,然后是eff1,然后是eff2,所以这意味着提交给firestore的值为零(因为它是在计算之前)计算确实计算出正确的答案它只是没有将答案提交给数据库。

如何更改我的代码以使其以正确的顺序执行?

// Triggered when the send new message form is submitted.
function onMessageFormSubmit(e) {
  e.preventDefault();
  //Calculate efficiency
  var preodo = 0
  var efficiency = 0
  firebase.firestore().collection('Vehicle').doc(reg.value).collection('Refuels').orderBy('Date', 'desc').limit(1)
    .onSnapshot(function(snapshot) {
      snapshot.docChanges().forEach(function(change) {
        preodo = change.doc.data().Odometer
        efficiency = (odo.value - preodo) / amount.value
        efficiency = efficiency.toFixed(4);
        console.log("eff1:" + efficiency)
      });
      console.log("eff2:" + efficiency)
    });
  //Save refuel transaction with all details form the form as well as the calculated efficiency        
  console.log("eff3:" + efficiency)
  saveMessage(reg.value, odo.value, date.value, amount.value, price.value, rebate.value, efficiency).then(function() {
    window.alert('Refuel submitted!')
    // Clear message text field and re-enable the SEND button.
    resetMaterialTextfield();
    toggleButton();
  });
}

【问题讨论】:

  • 我的猜测是,从未使用过 Google Firestore,onsnapshot 方法是异步的,但您的代码正在以同步方式运行 savemessage 方法。能否在onSnapshot 方法中添加Promise 并使用解析后的值继续程序流程?
  • 你能不能把saveMessage 代码上移到“eff2”行之后?
  • @carljdp,如果我这样做了,它会多次提交保存,就好像它在循环中一样
  • @JillianWittstock,我明白了。我没有更多建议(目前),perhaps this can be helpful 在进一步调试中。

标签: javascript html google-cloud-firestore


【解决方案1】:

Firestore 操作是异步的,因此您需要使用 Promise 来处理它们。完全按照您对 saveMessage() 所做的操作,但返回一个值

另外,请使用.get() 而不是.onSnapshot(),因为后者将继续侦听对引用文档所做的更改,您不需要这些更改,因为您在单击按钮时执行此操作。

function get_efficiency(regValue) {
    efficiency = -1
    // return a Promise which will return the efficiency after all computations are done
    return firebase.firestore().collection('Vehicle')
        .doc(reg.value)
        .collection('Refuels')
        .orderBy('Date', 'desc')
        .limit(1)
        .get()
        .then(function (querySnapshots) { // this will execute after all documents are fetched from the db
            querySnapshots.forEach(function(doc) {
                preodo = doc.data().Odometer
                efficiency = (odo.value - preodo) / amount.value
                efficiency = efficiency.toFixed(4);
                console.log("eff1:" + efficiency)
            });
            console.log("eff2:" + efficiency)
            return efficiency
        })
}


// Triggered when the send new message form is submitted.
function onMessageFormSubmit(e) {
    e.preventDefault();
    //Calculate efficiency
    var preodo = 0
    var efficiency = 0

    get_efficiency(reg.value)
        .then(function (efficiency) { // this will execute after you computed the efficiency
        // efficiency param is the one returned from the PROMISE from get_efficiency()
    
        //Save refuel transaction with all details form the form as well as the calculated efficiency        
        console.log("eff3:" + efficiency)
        saveMessage(reg.value, odo.value, date.value, amount.value, price.value, rebate.value, efficiency).then(function() {
            window.alert('Refuel submitted!')
            // Clear message text field and re-enable the SEND button.
            resetMaterialTextfield();
            toggleButton();
        });
    })
}

【讨论】:

    【解决方案2】:

    通过使用@Professor Abronsius 的建议,我将我的代码放入了Promise

    // Triggered when the send new message form is submitted.
    function onMessageFormSubmit(e) {
      e.preventDefault();
      let myPromise = new Promise(function(myResolve, myReject) {
        //Calculate efficiency
        var preodo = 0
        var efficiency = 0
        firebase.firestore().collection('Vehicle').doc(reg.value).collection('Refuels').orderBy('Date', 'desc').limit(1)
          .onSnapshot(function(snapshot) {
            snapshot.docChanges().forEach(function(change) {
              preodo = change.doc.data().Odometer
              efficiency = (odo.value - preodo) / amount.value
              efficiency = efficiency.toFixed(4);
              console.log("eff1:" + efficiency)
            });
            console.log("eff2:" + efficiency)
            myResolve(efficiency); // when successful
            myReject("Not able to calculate efficiency"); // when error
          });
      });
    
      // "Consuming Code" (Must wait for a fulfilled Promise)
      myPromise.then(
        function(efficiency) {
          //Save refuel transaction with all details form the form as well as the calculated efficiency        
          console.log("eff3:" + efficiency)
          saveMessage(reg.value, odo.value, date.value, amount.value, price.value, rebate.value, efficiency).then(function() {
            window.alert('Refuel submitted!')
            // Clear message text field and re-enable the SEND button.
            resetMaterialTextfield();
            toggleButton();
          });
        },
        function(error) {
          window.alert(error)
        }
      );
    }

    这行得通...它只向firestore提交一次,但是...它打印到控制台日志,如下所示: eff1, eff2, eff3, eff1, eff1, eff2.

    我现在很好奇为什么它会重复自己?重复这个并不重要,因为它不会影响数据库或用户界面,但我很好奇。

    【讨论】:

    • 它似乎为数据库中的每个条目重复循环,所以我第二次提交它循环 3 次,第三次提交循环 4 次,依此类推
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-01
    • 1970-01-01
    • 2012-09-08
    相关资源
    最近更新 更多