【问题标题】:Ajax callback is only called once on final iteration of loopAjax 回调仅在循环的最终迭代中调用一次
【发布时间】:2018-02-10 01:36:31
【问题描述】:

[编辑] 关于回调的新问题 [编辑]

我正在尝试使用 Ajax 和 Javascript 加载一些本地文本文件,但我无法让回调正常工作。 我有我的代码大纲:

 var theFiles = {
  one: null,
  two: null,
  three: null,
  four: null,
  five: null,
  six: null,
  seven: null
};
function callback(pos,arrayofwords) {

    theFiles[pos]=arrayofwords;
}

xhr = new XMLHttpRequest();

var getFiles = function(theFiles,callback) {
  for (var p in theFiles) {
    console.log("in getFile: " + p);
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4 && xhr.status == 200) {

        callback(p,xhr.responseText.split(/\r?\n/));
      }
     };

    xhr.open("GET", p + ".txt", true);
    xhr.send();
  }
}

本地存储文件 one.txt、two.txt、three.txt 等... 即使 for 循环为文件中的每个键调用 open(),回调也只会执行一次。只有文件中的最后一项(七个)被填充。 我不明白为什么。

更新 在@xianshenglu 提供答案后,我发现实际上不需要回调。这也有效

    var theFiles = {
  one: null,
  two: null,
  three: null,
  four: null,
  five: null,
  six: null,
  seven: null
};



var getFiles = function(theFiles) {
  for (let p in theFiles) {   //var to let
    let xhr = new XMLHttpRequest();  //move inside the loop
    console.log("in getFile: " + p);
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4 && xhr.status == 200) {

        theFiles[p]=xhr.responseText.split(/\r?\n/)); //no callback needed
      }
     };

    xhr.open("GET", p + ".txt", true);
    xhr.send();
  }
}

【问题讨论】:

  • 阅读my answer,我解释了做什么你应该做什么以及为什么

标签: javascript ajax callback


【解决方案1】:

试试这个:

var getFiles = function(theFiles, callback) {
    for (let p in theFiles) {
        let xhr = new XMLHttpRequest();
        console.log("in getFile: " + p);
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                console.log(xhr.responseText);//test if work;
                callback(p, xhr.responseText.split(/\r?\n/));
            }
        };

        xhr.open("GET", p + ".txt", true);
        xhr.send();
    }
};

解释:

如果您使用一个忙于发送和接收的 xhr 对象并告诉它发送另一个请求,它会停止执行任何操作并发送新请求。

关于 var 的另一种解释:

function f(a) {
  console.log(a);
}
for (var i = 0; i < 3; i++) {
  document.body.onclick = function() {
    f(i)
  };
}
html,
body {
  width: 100%;
  height: 100%;
}

点击body 3次,你总是得到3,最后一个值;所以,不要在循环中使用var,因为上面的代码几乎等于:

function f(a) {
  console.log(a);
}
var i;
for (i = 0; i < 3; i++) {
  document.body.onclick = function() {
    f(i);// not execute at once,when executing ,i already becomes the last one,which is 3;
  };
}

更多信息,做一些关于 var 提升的研究,你会得到很多,MDN

【讨论】:

  • 谢谢你.. 它现在每次通过循环调用回调,但每次'p'的值都是'7'最后一个值。
  • xhr.responseText 怎么样,这是最后一个吗?
  • 循环的每次迭代 xhr.responseText 都有正确的文件,但在 onreadystatechange 函数中 p 的值始终是最后一个“七”。
  • @user2250892 let p in theFiles,你在Files中使用了var p吗?
  • @user2250892,当你使用 var 时,它会得到最后一个,如果你让,它工作正常,我测试过
【解决方案2】:

另一种解决方案,使用 async/await 和 fetch。

let getFile = async (p) => {
    console.log("in getFile: " + p);
    let res = await fetch('/' + p + '.txt');
    let text = await res.text();
    return text.split(/\r?\n/);
}

let getFiles = async () => {
    for (let p in theFiles) theFiles[p] = await getFile(p);
}

getFiles();

更多关于fetchasync/await

【讨论】:

    【解决方案3】:

    您应该使用let 而不是var

    如果你使用 let 而不是 var 它将起作用 因为:

    for 循环运行非常快(在运行 ajax 之前) 所以如果你使用 var in for (var p in theFiles)p 值将在每个 循环的迭代,最后用最后一个值填充 theFiles,现在将启动 ajax 操作,所有操作都使用 pptheFiles的最后一项填充。

    但是如果我们使用 let 而不是 var 每个 p 会有所不同 比循环迭代中的另一个p。所以效果很好。

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多