简体   繁体   English

递归地进行多个AJAX调用是一个坏主意

[英]Making multiple AJAX calls recursively is a bad idea

I already gone through this question. 我已经经历了这个问题。 Are recursive AJAX calls a bad idea? 递归AJAX叫坏主意吗? Here answer provided by Justin Niessner is good (by using promises) But my problem is little bit different. 贾斯汀·尼斯纳(Justin Niessner)提供的答案很好(通过使用诺言),但我的问题有点不同。 I want to call 10 ajax calls recursively. 我想递归调用10 ajax calls Like when first ajax call completed , I render that data(provided by ajax call) in my view and at the same time I will call second ajax call.So my code sample will look like this: 就像第一次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);
                ....................................
            });
        });
    });

})();

I want to render each data as soon as possible. 我想尽快呈现每个数据。 So in success of every ajax call I am rendering that data. 因此,在每次ajax调用成功时,我正在渲染该数据。 Here are my problems : 这是我的问题:

Is there is any better of doing this ? 有什么更好的办法吗? can I use promises in this case ? 在这种情况下可以使用promises吗? ( rendering data is necessary as soon as possible ). 尽快提供数据是必要的 )。 If yes than how and if no than what is the best way of doing this kind of calls. 如果是,则为最佳方式,如果不是,则为最佳方式。

  1. Note : rendering data on ajax success is my priority. 注意:在ajax成功上渲染数据是我的首要任务。
  2. Edit - Browser support -latest chrome,firefox and IE-11. 编辑-浏览器支持-最新的chrome,firefox和IE-11。
  3. Edit - according to comments improvement : 编辑-根据评论的改进:
 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); } 

Nested Ajax calls work. 嵌套的Ajax调用有效。 There are some drawbacks though: 但是有一些缺点:

  • If you're doing real error handling, it can get quite messy with multiple nested ajax calls and you often end up repeating error handling at every level of the nesting. 如果您正在执行真正的错误处理,那么使用多个嵌套的ajax调用可能会变得非常混乱,并且您经常最终会在嵌套的每个级别重复进行错误处理。
  • In some people's opinion, deep nesting can lead to less readable code than other techniques 在某些人看来,与其他技术相比,深层嵌套可能导致代码的可读性降低
  • If any code in the nesting can throw exceptions, you need a lot of exception handlers to properly catch all the exceptions and it's difficult to propagate the errors cleanly - because these are async callbacks, you can't just catch the exceptions in one place. 如果嵌套中的任何代码都可能引发异常,则需要大量异常处理程序来正确捕获所有异常,并且很难清晰地传播错误-因为这些是异步回调,因此您不能只在一个地方捕获异常。

See Edits at End of Answer Now that the Intent of the Question has been Clarified 现在已经弄清楚问题的意图,请参见答案末尾的编辑

As for other ways to do this, there are some advantages to using promises. 至于其他方式,使用诺言有一些优势。 Since none of your calls depends upon the previous set of calls and you just want to insert the results in proper order, you can significantly speed up your end-to-end time by sending all the ajax requests at once and then just serialize the results back in order. 由于您的调用都不依赖于先前的调用集,而您只想按正确的顺序插入结果,因此可以通过一次发送所有ajax请求然后序列化结果来显着缩短端到端时间回到秩序。 That can be done with manual coding or it can be done fairly easily with promises. 这可以通过手动编码来完成,也可以通过promise轻松地完成。

You don't say what promise library you plan to use (there are several), but here's one done using Bluebird (though the code would be similar or identical with other libraries): 您没有说要使用什么promise库(有几个),但是这是使用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
    });

})();

This has the performance advantage of it requests all the data at once, but then processes the results in the original request order. 这具有性能优势,它可以一次请求所有数据,然后以原始请求顺序处理结果。 This shortens the end-to-end time compared to serializing like you had with request-response-request-response-request-response. 与像请求-响应-请求-响应-请求-响应那样进行序列化相比,这缩短了端到端的时间。 This starts with request-request-request and Promise.all does the work for us to put the results into the right order for us to process them in the order that we requested them. 首先从request-request-request和Promise.all进行工作,以使结果按正确的顺序排列,以便我们按请求的顺序处理它们。


If you want to display any column as soon as possible, you don't even have to wait for all to complete and the second part of the code can be this: 如果要尽快显示任何列,您甚至不必等待所有内容完成,代码的第二部分可以是:

// 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);
    });
});

Promises aren't benefiting you as much here as you could code a similar structure with your callback mechanism. 承诺在这里没有给您带来太多好处,因为您可以使用回调机制编写类似的结构。


Without promises, you could just use your original downloadAsync() function and do this: 没有承诺,您可以只使用原始的downloadAsync()函数并执行以下操作:

downloadAsync("mathmatics.json", renderData);
downloadAsync("science.json", renderData);
downloadAsync("english.json", renderData);

This will launch all three in parallel and render each one immediately as the data arrives. 这将并行启动所有三个,并在数据到达时立即渲染每个。


Or, if you had more than three and you put the filenames in an array of any length and you can do this: 或者,如果您有三个以上,并且将文件名放在任意长度的数组中,则可以执行以下操作:

["mathmatics.json", "science.json", "english.json"].forEach(function(item) {
   downloadAsync(item, renderData);
});

Since you're doing new browsers - your life can be a lot simpler with promises. 既然你正在做新的浏览器-你的生活可以简单很多与承诺。

You're checking for things not relevant since IE6, you can simplify your work a great deal. 您正在检查自IE6起不相关的内容,因此可以大大简化您的工作。

Here is how: 方法如下:

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();
    });
}

No need for the checks for XMLHttpRequest, no needs for the status checks, a simple onload - note we've also added an onerror so we don't silence errors. 不需要检查XMLHttpRequest,不需要状态检查,只需简单的onload-注意,我们还添加了onerror,因此我们不会使错误保持沉默。

Now, let's download all three at once: 现在,让我们一次下载所有三个:

// 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.
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM