函数在执行之前就已执行

时间:2019-05-14 20:27:45

标签: javascript node.js asynchronous synchronous

我有一个网页,可以听一些按钮的点击。按钮之一(“ generateReport”)向容器返回1行数据,另一个按钮(“ generateReporFromRange”)向容器返回一定范围的行。范围按钮本质上只是for循环中的单个按钮。

然后,我有了另一个函数(“ pBuyGauge”),该函数几乎可以使用数组创建HTML / CSS径向规以计算平均值。我的问题是pBuyGauge函数中的“ myArr”数组和“ average”变量分别返回一个空数组和null值,但仅在单击范围按钮时才返回!如果我再次单击它,它将计算值。我认为通过在generateReportFromRange的for循环结束时调用pBuyGauge意味着它在数组中具有值。但似乎要先计算自己。

<script>                       

export default {
  name: "pmReport",
  components: { myTable, appShell },

  data() {
    return {
      error: null,
      jobNumber: null,
      jobRangeMin: 0,
      jobRangeMax: 0,
      rowData: [],
      pBuyArr: []
    };

  },

  methods: {

    generateReportFromRange() {

      let jobIds = range(this.jobRangeMin, (this.jobRangeMax+1));

      jobIds.forEach(id => {

        this.error = "Loading..."; // show loading status in error indicator
        this.generateReport(id.toString());
        this.error = "Loading..."; // show loading status in error indicator

      });

      this.error = ""; // clear error on completion
      this.jobRangeMin = 0;
      this.jobRangeMax = 0;

      this.pBuyGauge();

    },

    generateReport(id = null) {

      fetch("/api/pm", {
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json"
        },
        credentials: "include",
        method: "POST",
        body: JSON.stringify({
          jobnum: id || this.jobNumber,
          user: this.$store.state.user
        })

      })
        .then(r =>
          r.json().then(json => {
            if (!json["Job Number"]) {
              this.error = "You do not have access to the specified record.";
              return;
            }


            this.error = "";
            this.cleanNumbers(json);
            this.columnNames(json);

            this.pBuyArr.push(parseInt(json["Percent Buy"])); //For some reason it's important this line is here and not above

            console.log("RRROp", r)

          })
        )
        .catch(e => {
          console.error("PM Fetch error", e); // eslint-disable-line
          this.error = e.message;
        });

    },

    pBuyGauge() {

      let myArr = this.pBuyArr; ////ALWAYS EMPTY FIRST TIME

      var pBuy = 0;
      var total = 0;
      var i=0;
      var average = 0;

      for(i = 0; i < (myArr.length); i++) {

          pBuy = myArr[i];
          total = total + pBuy;
      }

      average = total / myArr.length;

      console.log(JSON.stringify(myArr))
      console.log("My avg is:", JSON.stringify(average))

      var cf = 943;

      if (average >= 21) {

        var semi_cf = 0;

      }else if (average <= 0){

        var semi_cf = 707;

      }else{    

        var semi_cf = 707-(average*33.67);

      }

      document.querySelector('#mask').setAttribute("stroke-dasharray", semi_cf + "," + cf);

    }

  },

1 个答案:

答案 0 :(得分:0)

您调用fetch(),这是异步的。它将在后台启动对服务器的请求。同时,您的代码将继续执行,届时您的数组将为空。将来的某个时候,调用会完成并回调,返回的Promise将被完全填充,并且链接到它的.then回调将被执行。因此,数组将在某些时候被填充。现在,您要等待继续到将来某个地方。为此,首先,通过从您的承诺中返回所有承诺并将其存储在数组中来收集所有承诺:

  generateReport(id = null) {
   return fetch("/api/pm", {
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json"
    },
    credentials: "include",
    method: "POST",
    body: JSON.stringify({
      jobnum: id || this.jobNumber,
      user: this.$store.state.user
    })
  })
  .then(r => r.json())
  .then(json => {
    if (!json["Job Number"]) {
       // proper error handling involves rejecting the promise:
       throw new Error("You do not have access to the specified record.");
    }
    /*this.cleanNumbers(json);
    this.columnNames(json); Should this function really cause side effects ? */

   return parseInt(json["Percent Buy"]); // Thats what the returned promise chain resolves to
  });
 }


 //...
const promises = [];

 this.error = "Loading..."; 

jobIds.forEach(id => { 
    promises.push(this.generateReport(id.toString()));        
});

现在我们有了一个Promises数组,我们可以在其上调用Promise.all,它将把这组Promise变成一个包含Promise结果的Promise:

  Promise.all(promises).then(result => {
    console.log(result); // << thats what you are looking for
    //... your code to work with the result
 });