JavaScript如何确定何时在循环中完成AJAX调用
在过去的几天里,我一直在努力解决这个问题,并在StackOverflow和其他网站上阅读了各种解决方案 我正在构建一个站点,该站点从外部源获取XML数据,然后根据结果获取更多XML以构建网络图问题是,我必须等到这个AJAX调用循环(可能会循环成更多的AJAX调用)完成后才能绘制 我不知道这是否只是一个特别高的认知负荷,但它确实让我感到困惑 我的代码:JavaScript如何确定何时在循环中完成AJAX调用,javascript,jquery,ajax,Javascript,Jquery,Ajax,在过去的几天里,我一直在努力解决这个问题,并在StackOverflow和其他网站上阅读了各种解决方案 我正在构建一个站点,该站点从外部源获取XML数据,然后根据结果获取更多XML以构建网络图问题是,我必须等到这个AJAX调用循环(可能会循环成更多的AJAX调用)完成后才能绘制 我不知道这是否只是一个特别高的认知负荷,但它确实让我感到困惑 我的代码: function cont(outerNodes) { for (var i = 0; i < outerNodes.length
function cont(outerNodes) {
for (var i = 0; i < outerNodes.length; i++) {
var node = outerNodes.pop();
getXML(node["label"], node["id"]);
}
// I want the code to wait until loop is done, and then draw.
draw(nodes, edges);
}
function getXML(term, fromId) {
var url = someURL;
$.ajax({
url: url,
dataType: "xml",
success: function(result) {
var outerNodes = process(result, fromId, term);
cont(outerNodes);
}
});
}
功能控制(外部节点){
对于(变量i=0;i
注意:我理解我可能完全误解了JavaScript的同步性,我很可能是这样。在过去,我成功地使用了回电和承诺,但我似乎无法理解这一点
如果我还不完全清楚,请让我知道
我确实尝试过实现在process()函数中递增的排序计数器,如下所示:
if (processCount < 15) {
for (var i = 0; i < outerNodes.length; i++) {
var node = outerNodes.pop();
getXML(node["label"], node["id"]);
}
} else {
draw(nodes, edges);
}
if(进程计数<15){
对于(变量i=0;i
然而,这最终导致了几次draw()调用,这使我的性能非常糟糕。如果在多次测试之后,您知道它不会超过5秒。。。您可以使用setTimeout
function cont(outerNodes) {
for (var i = 0; i < outerNodes.length; i++) {
var node = outerNodes.pop();
getXML(node["label"], node["id"]);
}
// Display a 5 second progress bar here
setTimeout(function(){ draw(nodes, edges); },5000);
}
功能控制(外部节点){
对于(变量i=0;i
解决此问题的最佳方法应该是使用承诺或回调。
如果你真的想避免承诺或回访(尽管我不知道为什么…)
你可以用柜台试试
let processCount = 0;
// Increasing the processCount in getXML callback method
function getXML(term, fromId) {
var url = someURL;
$.ajax({
url: url,
dataType: "xml",
success: function(result) {
processCount++;
var outerNodes = process(result, fromId, term);
cont(outerNodes);
}
});
}
for (var i = 0; i < outerNodes.length; i++) {
var node = outerNodes.pop();
getXML(node["label"], node["id"]);
}
while (processCount < outerNodes.length) {
// do nothing, just wait'
}
draw(nodes, edges);
让processCount=0;
//增加getXML回调方法中的processCount
函数getXML(术语,fromId){
var url=someURL;
$.ajax({
url:url,
数据类型:“xml”,
成功:功能(结果){
processCount++;
var outerNodes=过程(结果、fromId、术语);
续(外节点);
}
});
}
对于(变量i=0;i
我们可以使用支持良好的新API和语言结构。和
fetchapi使用承诺。可以期待承诺。的for…of
循环知道等待
并且在等待
通过之前不会继续循环
// Loop through, one-at-a-time
for (const node of outerNodes) {
// Make the HTTP request
const res = await fetch(someUrl);
// Do something with the response here...
}
不要忘记一个尝试
/捕获
(它也适用于等待
),然后检查。Brad的回答将代码更改为同步,对我来说,这违背了目的。如果您一直在等待所有请求完成,那么可能需要一段时间,而普通浏览器可以处理多个请求
你在最初的问题中遇到的问题是范围问题。因为每次调用cont(outerNodes)
都会触发它自己的作用域,所以它不知道这些调用在做什么。因此,基本上,如果您调用cont(outerNodes)
两次,每个调用都将处理自己的outerNodes
列表,然后调用draw
。
解决方案是在不同的作用域之间共享信息,这可以用一个但最好是两个全局变量来完成:一个用于跟踪活动进程,一个用于跟踪错误
var inProcess = 0;
var nrErrors = 0;
function cont(outerNodes) {
//make sure you have outerNodes before you call outerNodes.length
if (outerNodes) {
for (var i = 0; i < outerNodes.length; i++) {
var node = outerNodes.pop();
inProcess++; //add one more in process
getXML(node["label"], node["id"]);
}
}
//only trigger when nothing is in proces.
if (inProcess==0) {
// I want the code to wait until loop is done, and then draw.
draw(nodes, edges);
}
}
function getXML(term, fromId) {
var url = someURL;
$.ajax({
url: url,
dataType: "xml",
success: function(result) {
var outerNodes = process(result, fromId, term);
inProcess--; //one is done
cont(outerNodes);
},
error: function() {
inProcess--; //one is done
nrErrors++; //one more error
cont(null); //run without new outerNodes, to trigger a possible draw
}
});
}
var-inProcess=0;
var nErrors=0;
功能控制(外部节点){
//在调用outerNodes.length之前,请确保您有outerNodes
if(外节点){
对于(变量i=0;i
请注意,我跟踪nErrors
,但不做任何处理。您可以使用它一起停止进一步的处理,或者警告用户绘制未完成
[重要]请记住,这在javascript
中有效,因为它最多只能模拟多线程。这意味着调用inProcess--代码>然后紧接着cont(外部节点)代码>总是在彼此之后直接执行
如果要将其移植到真正的多线程环境中,很可能是cont(null)的另一个作用域/版本代码>将插入