我希望在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中有新的await
和async
,但我不想使用那些前沿的东西。
答案 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++;
}
};