如果没有jQuery,javascript如何检查多个ajax调用是否已经完成,一旦有了,就执行一段代码?

时间:2016-01-02 20:08:37

标签: javascript ajax

我已经知道如何在jQuery中做到这一点(哦,男孩很容易),但我很好奇如何在没有jQuery的情况下在基本的javascript中完成。毕竟,jQuery IS javascript,以及可以在一个中完成的任何事情都可以在另一个中完成(而不是像某些人想象的那样困难!)

请帮助满足我的好奇心!我想学习基本概念〜

一种常见的场景 - 用户执行多个ajax调用,并且只有在两次调用完成后才能执行一段代码。如何实现这一目标?

这是一个常见场景的简单示例。这是我到目前为止所尝试过的,(但没有奏效)。我知道它不起作用的原因是因为在javascript中,一次只能处理一个ajax调用。那么,在没有jQuery的情况下执行此操作的正确方法是什么?

//gets result html code, for a settings div inside a log panel
//this page also inserts some info into my database
//it has to run first and finish first before second ajax call, runs
var xmlhttp;
if (window.XMLHttpRequest) xmlhttp=new XMLHttpRequest(); 
else  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
xmlhttp.open("POST","/scripts/post_login_panel_actions.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("settings_button_activate=1&display_image_url="+encodeURIComponent(settings_display_picture_url));

//gets result html code, for the login panel inside of which, there is a settings div
//this has to run after, so that it can render the new stuff that was added to my database
var xmlhttp2;
if (window.XMLHttpRequest) xmlhttp2=new XMLHttpRequest(); 
else xmlhttp2=new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp2.open("POST","/scripts/post_login_panel_actions.php",true);
xmlhttp2.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp2.send("settings_refresh_login_panel=1");     

//after both calls have been completed, the new login panel should be rendered
//and then, the new settings-div should be rendered inside of the new login panel
xmlhttp.onreadystatechange=function()  { 
    if (xmlhttp.readyState==4 && xmlhttp.status==200 && xmlhttp2.readyState==4 && xmlhttp2.status==200) {
        document.getElementById("login_panel").innerHTML=xmlhttp2.responseText;
        document.getElementById("login_panel_settings").innerHTML=xmlhttp.responseText;    }    }

编辑后,阅读答案,评论并尝试编写更多代码:

lleaff的答案是最好的和神圣的狗屎真的多才多艺,你可以简单地复制粘贴它,它将神奇地工作,对于不同的变量和场景。我已经接受了它作为正确的答案。

但是这里有一些奖励信息可以帮助那些可能偶然发现这个页面的人......我自己想出了第二种(更粗糙,更愚蠢!)控制两者的方法

  1. 执行两个ajax调用的顺序(在调用2真正需要在调用2开始之前完成的特殊情况下
  2. 只有当两个ajax调用完成
  3. 时才会发生最终的函数调用

    这里的问题是,javascript的设计并不是为了让你轻松检查“当变量Y改变时的火焰动作X”之类的东西 - 所以有些人可能很难弄清楚如何使用答案人们告诉你“保留一个全局变量来跟踪已经完成的事情”。

    你可以触发支票,每次onreadystatechange函数都会意识到......就绪状态已经改变。我原来实现的问题是我只检查了ONE的就绪状态ajax调用。

    更粗略(但易于理解!)解决方案,希望这会为观看此主题的人提供额外帮助:

    //Declare your ajax variables~
    var xmlhttp;
    if (window.XMLHttpRequest) xmlhttp=new XMLHttpRequest(); 
    else  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
    var xmlhttp2;
    if (window.XMLHttpRequest) xmlhttp2=new XMLHttpRequest(); 
    else xmlhttp2=new ActiveXObject("Microsoft.XMLHTTP");
    
    //Step 1 (first ajax call) code will begin executing here
    xmlhttp.open("POST","/scripts/post_login_panel_actions.php",true);
    xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xmlhttp.send("settings_button_activate=1&display_image_url="+encodeURIComponent(document.getElementById("settings_display_picture_url").value));
    
    //Step 2 (second ajax call) this function will be called ... later in the code!
    function ajax_call_two() {
        xmlhttp2.open("POST","/scripts/post_login_panel_actions.php",true);
        xmlhttp2.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xmlhttp2.send("settings_refresh_login_panel=1");
        xmlhttp2.onreadystatechange=function()  { 
            if (xmlhttp2.readyState==4 && xmlhttp2.status==200) {
                //when Step 2 is finished, Step 3 is called.
                stuff_to_do_after_all_ajax_calls_are_finished();    }    }   }  
    
    //Step 3 (stuff_to_do_after_all_ajax_calls_are_finished. literally.) this function will be called ... later in the code!
    function stuff_to_do_after_all_ajax_calls_are_finished() {
        document.getElementById("login_panel").innerHTML=xmlhttp2.responseText;
        document.getElementById("login_panel_settings").innerHTML=xmlhttp.responseText;    } 
    
    //When Step 1 is finished, Step 2 is called.
    xmlhttp.onreadystatechange=function()  { 
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            ajax_call_two();    }    } 
    

1 个答案:

答案 0 :(得分:5)

只需将您传递给xmlhttp.onreadystatechange的函数命名为并将其分配给每个请求的onreadystatechange属性。

以下是我如何概括解决此问题的方法:

function requestsAreComplete(requests) {
    return requests.every(function (request) {
        return request.readyState == 4;
    });
} 

function unsuccessfulRequests(requests) {
    var unsuccessful = requests.filter(function (request) {
         return request.status != 200;
    };
    return unsuccessful.length ? unsuccessful : null;
}

function onRequestsComplete(requests, callback) {   
    // Wrap callback into a function that checks for all requests completion     
    function sharedCallback() {
        if (requestsAreComplete(requests)) {
            callback(requests, unsuccessfulRequests(requests));
        }
    }

    // Assign the shared callback to each request's `onreadystatechange`
    requests.forEach(function (request) {
        request.onreadystatechange = sharedCallback;
    });
}

你可以这样使用它:

onRequestsComplete([xmlhttp, xmlhttp2], function(requests, unsuccessful) {
    if (unsuccessful) { return; } // Abort if some requests failed

    document.getElementById("login_panel").innerHTML=requests[1].responseText;
    document.getElementById("login_panel_settings").innerHTML=requests[0].responseText;
});