Javascript,在for循环中调用异步函数

时间:2017-03-06 06:10:57

标签: javascript asynchronous callback

我希望在for循环中调用异步函数。我遇到了很大的麻烦,并且遇到了各种错误,例如未定义的变量等等。

Evaluator.prototype.asyncEval = function(predictor) {
let self = this;
let metric = 0; //METRICS SHOULD BE UPDATED BY ASYNC FUNCTION

 for (let i = 1; i < this.fullTraces.length; i++) {
      (function(index){
          let deltaTime = self.fullTraces[i][2] - this.fullTraces[i-1][2];
          let subTraces = self.fullTraces.slice(0, i);

          predictor.predict(subTraces, (dist) => { // ASYNC FUNCTION
              if (dist !== null) {
                  let result = dist.getTopK(1);
                  let pX = result[0][0][0];
                  let pY = result[0][0][1];
                  let x = self.fullTraces[i][0];
                  let y = self.fullTraces[i][1];
                  let a = pX - x;
                  let b = pY - y;

                  metric += Math.sqrt(a*a + b*b);
              }
          });
      }(i));
  }
  metric /= this.fullTraces.length - 1;
  return metric;

}

我的异步函数predictor.predict()实际上是使用POST请求从我的Web服务器获取结果。

YourPredictor.prototype.predict = function(trace, callback) {
      return asyncPostRequest('https://0.0.0.0:5000/prediction', trace, responseText => {
              prediction = JSON.parse(responseText);
              let pred = [prediction['xs'], prediction['ys'], 'm'];
              let dist = Dist.NaiveDistribution.from(pred, mouseToKey);
              dist.set(pred, 1);
              callback(dist);
      });
  }

我怎样才能让它发挥作用?我在Chrome上运行此功能。我知道ES7中有新的awaitasync,但我不想使用那些前沿的东西。

3 个答案:

答案 0 :(得分:0)

你需要重构代码以用自调用循环替换循环,这样每次调用异步时,都会返回它的结果,然后检查迭代,如果我

由于主代码是异步的,因此您还需要回调初始调用函数(下面的doneCallback)。

实施例

我在原始代码中留下了预期可以使用的代码,但在此处进行了一些更改。

function Evaluator() {}; // dummy for test
Evaluator.prototype.asyncEval = function(predictor, doneCallback) {
  let self = this;
  let metric = 0;
  let length = 10; //this.fullTraces.length;
  let i = 1;

  // replaces for-loop
  (function loop() {
    self.predict(0, (dist) => {
      // ...
      metric += dist;
      if (++i < length) loop();
      else {
        // ...
        doneCallback(metric);
      }
    });
  })();
}

// note: I changed prototype parent in this example
Evaluator.prototype.predict = function(trace, callback) {
  //...
  setTimeout(callback, 100, Math.random() * 100); // simulate async call
}

// TEST
var test = new Evaluator();
test.asyncEval(0, function(result) {
  document.querySelector("div").innerHTML = result;
});
<div>Calcing...</div>

将原始代码留在预定位置的示例:

function Evaluator() {}; // dummy for test
Evaluator.prototype.asyncEval = function(predictor, doneCallback) {
  let self = this;
  let metric = 0; //METRICS SHOULD BE UPDATED BY ASYNC FUNCTION
  let length = 10; //this.fullTraces.length;
  let i = 1;

  // replaces for-loop
  (function loop() {
    //let deltaTime = self.fullTraces[i][2] - this.fullTraces[i - 1][2];
    //let subTraces = self.fullTraces.slice(0, i);

    self.predict(0, (dist) => { // ASYNC FUNCTION
      //predictor.predict(subTraces, (dist) => { // ASYNC FUNCTION
      /*if (dist !== null) {
      	let result = dist.getTopK(1);
      	let pX = result[0][0][0];
      	let pY = result[0][0][1];
      	let x = self.fullTraces[i][0];
      	let y = self.fullTraces[i][1];
      	let a = pX - x;
      	let b = pY - y;

      	metric += Math.sqrt(a * a + b * b);
      }*/
      metric += dist;
      if (++i < length) loop();
      else {
        //metric /= this.fullTraces.length - 1;
        //return metric; <- don't use, instead use:
        doneCallback(metric);
      }
    });
  })();
}

// note: I changed prototype parent in this example
Evaluator.prototype.predict = function(trace, callback) {
  setTimeout(callback, 100, Math.random() * 100); // simulate async call
  /*return asyncPostRequest('https://0.0.0.0:5000/prediction', trace, responseText => {
          prediction = JSON.parse(responseText);
          let pred = [prediction['xs'], prediction['ys'], 'm'];
          let dist = Dist.NaiveDistribution.from(pred, mouseToKey);
          dist.set(pred, 1);
          callback(dist);
  });*/
}

// TEST
var test = new Evaluator();
test.asyncEval(0, function(result) {
  document.querySelector("div").innerHTML = result;
});
<div>Calcing...</div>

答案 1 :(得分:0)

如果您不想使用async + await组合,我建议您查看这篇文章。 Asynchronous for cycle in JavaScript

我正在使用这个asyncLoop函数,它运行得很好:

该函数有三个参数:1)迭代,2)循环回调函数和3)完成回调函数, 看看代码:

function promise1(param){
    return new Promise((resolve, reject) => setTimeout(() => { resolve(`Promise1 ${param} Done`)}, 2000))
}


function asyncLoop(iterations, func, callback) {
    var index = 0;
    var done = false;
    var loop = {
        next: function() {
            if (done) {
                return;
            }

            if (index < iterations) {
                index++;
                func(loop);

            } else {
                done = true;
                callback();
            }
        },

        iteration: function() {
            return index - 1;
        },

        break: function() {
            done = true;
            callback();
        }
    };
    loop.next();
    return loop;
}

var asyncProc = ["Process1", "Process2", "Process3"]
asyncLoop
(
    asyncProc.length,
  (loop) => {   promise1(asyncProc[loop.iteration()]).then((msg) =>{ console.log(msg); loop.next() }) },
  () => { console.log("ALL DONE!")});

答案 2 :(得分:0)

如果异步修改“metric”,则无法同步返回该值。您需要将回调传递给您的方法,以便在准备就绪时可以返回“指标”。

Evaluator.prototype.asyncEval = function (predictor, callback) {

    let self = this;
    let metric = 0; //METRICS SHOULD BE UPDATED BY ASYNC FUNCTION
    let callbacks = 0; // Keep a counter for the asynchronous callbacks
    for (let i = 1; i < self.fullTraces.length; i++) {
        let deltaTime = self.fullTraces[i][2] - this.fullTraces[i - 1][2];
        let subTraces = self.fullTraces.slice(0, i);

        // Queue up an asynchronous callback
        predictor.predict(subTraces, (dist) => { // ASYNC FUNCTION
            if (dist !== null) {
                let result = dist.getTopK(1);
                let pX = result[0][0][0];
                let pY = result[0][0][1];
                let x = self.fullTraces[i][0];
                let y = self.fullTraces[i][1];
                let a = pX - x;
                let b = pY - y;

                metric += Math.sqrt(a * a + b * b);
            }

            // Decrement the counter and check if we're done
            if (--callbacks === 0) {
                callback(metric / (self.fullTraces.length - 1));
            }
        });

        // Increment the counter
        callbacks++;
    }
};
相关问题