我已经完成了这个问题。
Are recursive AJAX calls a bad idea?
Justin Niessner提供的答案很好(通过使用承诺)但我的问题有点不同。
我想以递归方式调用10 ajax calls
。就像第一次ajax调用完成时一样,我在我的视图中渲染该数据(由ajax调用提供),同时我将调用第二个ajax调用。所以我的代码示例将如下所示:
(function() {
var downloadAsync = function(url, callback) {
var httpRequest;
if (window.XMLHttpRequest) {
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
callback(httpRequest.responseText);
}
}
httpRequest.open("GET", url, true);
httpRequest.send();
}
function renderData(data) {
//data render logic
}
downloadAsync("mathmatics.json", function(response) {
renderData(response);
downloadAsync("science.json", function(response) {
renderData(response)
downloadAsync("english.json", function(response) {
renderData(response);
....................................
});
});
});
})();
我想尽快呈现每个数据。因此,在每次ajax调用成功时,我都在渲染数据。 这是我的问题:
这样做有什么好处吗?我可以在这种情况下使用promises
吗? (渲染数据
有必要尽快)。如果是,那么如何以及如何不是进行此类呼叫的最佳方式。
var array = ["mathematics.json", "science.json", "english.json"]; for (var i = 0; i < array.length; i++) { downloadAsync(array[i], renderData); } function renderData(data) { console.log(data); }
答案 0 :(得分:2)
嵌套的Ajax调用工作。但是有一些缺点:
请参阅“答案结束时的编辑”,现在问题的意图已经澄清
至于其他方法,使用promises有一些好处。由于您的调用都不依赖于之前的调用集,并且您只想按正确的顺序插入结果,因此您可以通过立即发送所有ajax请求然后序列化结果来显着加快端到端时间回来了。这可以通过手动编码完成,也可以通过promises轻松完成。
你没有说你计划使用什么诺言库(有几个),但这里是使用Bluebird完成的(虽然代码与其他库类似或相同):
(function() {
// downloadAsync now returns a promise rather than uses a callback
function downloadAsync(url) {
return new Promise(function(resolve, reject) {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
resolve(httpRequest.responseText);
} else {
reject(httpRequest.status);
}
}
}
httpRequest.open("GET", url, true);
httpRequest.send();
}
}
function renderData(data) {
//data render logic
}
var items = ["mathmatics.json", "science.json", "english.json"];
var promises = items.map(function(path) {
return downloadAsync(path);
});
// Promise.all collects all the promise results and
// calls .then only when all the promises have completed
Promise.all(promises).then(function(data) {
data.forEach(renderData)
}).catch(function(e) {
// handle errors here
});
})();
这具有以下性能优势:它一次请求所有数据,但随后按原始请求顺序处理结果。与序列化相比,这缩短了端到端时间,就像使用request-response-request-response-request-response一样。这开始于request-request-request和Promise.all为我们做的工作是将结果按正确的顺序排列,以便我们按照我们要求的顺序处理它们。
如果要尽快显示任何列,您甚至不必等待所有列完成,代码的第二部分可以是:
// note we are passing an index here so you know which column it is in case that isn't
// already specified in the data
function renderData(index, data) {
//data render logic
}
// are you sure you want a leading / on only one of these three?
var items = ["mathmatics.json", "science.json", "english.json"];
items.forEach(function(value, index) {
downloadAsync(value).then(function(data) {
renderData(index, data);
});
});
Promise并没有让你受益,因为你可以使用你的回调机制编写类似的结构。
如果没有承诺,您可以使用原始downloadAsync()
功能并执行此操作:
downloadAsync("mathmatics.json", renderData);
downloadAsync("science.json", renderData);
downloadAsync("english.json", renderData);
这将并行启动所有三个并在数据到达时立即渲染每个。
或者,如果你有三个以上,你把文件名放在任何长度的数组中,你可以这样做:
["mathmatics.json", "science.json", "english.json"].forEach(function(item) {
downloadAsync(item, renderData);
});
答案 1 :(得分:0)
由于您正在使用新的浏览器 - 您的生活可以通过承诺简化很多。
您正在检查自IE6以来不相关的内容,您可以大大简化您的工作。
以下是:
function downloadAsync(url){
return new Promise(function(fulfill, reject){
var xhr = new XMLHttpRequest;
xhr.open("GET", url);
xhr.onload = function(){ resolve(xhr.responseText); });
xhr.onerror = reject;
xhr.send();
});
}
不需要检查XMLHttpRequest,不需要状态检查,简单的onload - 注意我们还添加了一个错误,所以我们不会使错误沉默。
现在,让我们一次下载所有三个:
// your pages
var pages = ["mathmatics.json", "science.json", "english.json"]
// your downloads and renders
var promises = pages.map(downloadAsync).
/*map(JSON.parse).*/
map(renderData);
Promise.all(promises).then(function(){
// code here runs when it's all done.
});