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

Javascript 递归地进行多个AJAX调用是个坏主意,javascript,jquery,ajax,recursion,promise,Javascript,Jquery,Ajax,Recursion,Promise,我已经问过这个问题了。 在这里,贾斯汀·尼斯纳提供的答案是好的(通过使用承诺),但我的问题有点不同。 我想递归调用10个ajax调用。与第一个ajax调用完成时一样,我在视图中呈现该数据(由ajax调用提供),同时调用第二个ajax调用 (function() { var downloadAsync = function(url, callback) { var httpRequest; if (window.XMLHttpRequest) {

我已经问过这个问题了。 在这里,贾斯汀·尼斯纳提供的答案是好的(通过使用承诺),但我的问题有点不同。 我想递归调用10个ajax调用。与第一个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调用成功后,我都会呈现这些数据。 以下是我的问题:

还有比这更好的方法吗?在这种情况下,我可以使用
承诺吗?(渲染数据
必须尽快执行此操作)。如果是,那么如何打电话;如果不是,那么打这种电话的最佳方式是什么

  • 注意:在ajax上成功呈现数据是我的首要任务
  • 编辑-浏览器支持-最新的chrome、firefox和IE-11
  • 编辑-根据改进意见:
  • var数组=[“mathematics.json”、“science.json”、“english.json”];
    对于(var i=0;i

    嵌套Ajax调用可以工作。但也有一些缺点:

    • 若您正在进行真正的错误处理,那个么多个嵌套ajax调用可能会变得非常混乱,并且您经常会在嵌套的每个级别重复错误处理
    • 在一些人看来,与其他技术相比,深度嵌套可能导致可读性较差的代码
    • 如果嵌套中的任何代码都可以抛出异常,那么您需要大量异常处理程序来正确捕获所有异常,并且很难干净地传播错误-因为这些是异步回调,您不能只在一个位置捕获异常
    既然问题的意图已经澄清,请参见答案末尾的编辑内容

    至于其他方法,使用承诺有一些好处。由于您的调用都不依赖于前一组调用,并且您只想按正确的顺序插入结果,因此可以通过一次发送所有ajax请求,然后按顺序将结果序列化,从而显著加快端到端的时间。这可以通过手工编码完成,也可以通过承诺轻松完成

    您没有说您计划使用哪个promise库(有几个),但这里有一个是使用Bluebird完成的(尽管代码与其他库类似或相同):

    它的性能优势是一次请求所有数据,然后按原始请求顺序处理结果。与使用请求-响应进行序列化相比,这缩短了端到端的时间。这从请求和承诺开始。所有的工作都是为了我们将结果放入正确的顺序,以便我们按照我们要求的顺序处理它们


    如果希望尽快显示任何列,甚至不必等待全部完成,代码的第二部分可以是:

    // 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);
        });
    });
    
    在这里,承诺并没有像用回调机制编写类似结构那样让您受益匪浅


    如果没有承诺,您可以使用原始的
    downloadsync()
    函数执行以下操作:

    downloadAsync("mathmatics.json", renderData);
    downloadAsync("science.json", renderData);
    downloadAsync("english.json", renderData);
    
    这将并行启动所有三个,并在数据到达时立即呈现每一个


    或者,如果您有三个以上的文件名,并且将文件名放入任意长度的数组中,则可以执行以下操作:

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

    既然你正在开发新的浏览器,你的生活会因为承诺而变得简单得多

    您正在检查自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-注意,我们还添加了一个onerror,这样我们就不会消除错误

    现在,让我们同时下载这三个:

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

    既然您不发送任何数据,那么首先需要嵌套调用的原因是什么?如果只是为了让它们保持有序,可以更快地发送它们并使用承诺来保持有序如果你只是为了让数据保持有序,你可以在一个简单的循环中调用所有ajax函数,浏览器将对它们进行排队,但它们当然不会按顺序完成,你必须自己保持顺序,但这很容易,即使没有承诺,也只需向
    renderData
    函数传递一个索引,就可以知道请求完成了什么,等等@charlietfl抱歉我的错误,编辑了这个问题。仍然没有解释为什么不能简单地创建url数组和循环数组。@charlietfl我像你说的那样包含了代码。我很想知道,在这种情况下,这是最好的解决办法吗?或者我可以改进它?@pandit-注意:根据您的目标浏览器版本,您可能需要使用诸如Bluebird或Q之类的Promise库来保证Promise支持。我有10列,我在一列中显示每个ajax调用的数据,我的想法是尽快显示数据。这就是我这样做的原因。在您的方法中,只有当所有ajax调用完成时,我才能呈现整个数据。@pandit-我这样编码,因为您的原始代码就是这样工作的(它一次执行一个),我认为您希望这样。如果需求或愿望不同,则不必如此。我可以在我的回答中添加一个这样的例子。确切地说,我担心的是,只有“承诺在这里并没有像您可以用回调机制编写相同的结构那样让您受益。”您能否提供承诺实时用例的好链接。非常感谢。直到今天,我还从未见过与promises和Array#forEach一起使用
    if(window.XMLHttpRequest)
    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();
        });
    }
    
    // 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.
    });