web-dev-qa-db-fra.com

Comment puis-je obtenir que l'exécution du code JavaScript attende jusqu'à ce qu'une AJAX demande avec script est chargé et exécuté?

Dans mon application, j'utilise Ext.Ajax.request pour charger les scripts que j'exécute avec eval.

Le problème est que, comme il faut un certain temps pour terminer la demande AJAX, le code est ensuite exécuté, ce qui nécessite des variables figurant dans le script chargé via AJAX. Dans cet exemple, je montre comment c'est le cas. Comment puis-je modifier ce code afin que l'exécution du code JavaScript après AJAX attende que le script de l'appel AJAX ait été chargé et exécuté?

testEvalIssue_script.htm:

<script type="text/javascript">
    console.log('2. inside the ajax-loaded script');
</script>

main.htm:

<html>
    <head>
        <script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="ext/ext-all-debug.js"></script>
        <script type="text/javascript">
            function loadViewViaAjax(url) {
                Ext.Ajax.request({
                    url: url,
                    success: function(objServerResponse) {
                        var responseText = objServerResponse.responseText;
                        var scripts, scriptsFinder=/<script[^>]*>([\s\S]+)<\/script>/gi;
                        while(scripts=scriptsFinder.exec(responseText)) {
                            eval.call(window,scripts[1]);
                        }
                    }
                });
            }

            console.log('1. before loading ajax script');
            loadViewViaAjax('testEvalIssue_script.htm');
            console.log('3. after loading ajax script');
        </script>
    </head>
    <body>

    </body>

</html>

sortie:

1. before loading ajax script
3. after loading ajax script
2. inside the ajax-loaded script

Comment puis-je obtenir la sortie dans le bon ordre, comme ceci:

1. before loading ajax script
2. inside the ajax-loaded script
3. after loading ajax script
17
Edward Tanguay

Ajax est asynchrone, cela signifie que l'appel ajax est envoyé mais votre code continue à fonctionner aussi heureux qu'avant, sans s'arrêter. Ajax n'arrête pas/met en pause l'exécution jusqu'à ce qu'une réponse soit reçue. Vous devrez ajouter une fonction de rappel supplémentaire ou quelque chose du genre.

<html>
    <head>
        <script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="ext/ext-all-debug.js"></script>
        <script type="text/javascript">
            function loadViewViaAjax(url, callback) {
                Ext.Ajax.request({
                    url: url,
                    success: function(objServerResponse) {
                        var responseText = objServerResponse.responseText;
                        var scripts, scriptsFinder=/<script[^>]*>([\s\S]+)<\/script>/gi;
                        while(scripts=scriptsFinder.exec(responseText)) {
                            eval.call(window,scripts[1]);
                        }
                        callback.call();
                    }
                });
            }

            console.log('1. before loading ajax script');
            var afterAjax = function(){
                console.log('3. after loading ajax script');
            }
            loadViewViaAjax('testEvalIssue_script.htm', afterAjax);
        </script>
    </head>
    <body>

    </body>

</html>
12
ChrisR

Comme l'appel ajax est asynchrone, si vous souhaitez exécuter quelque chose qui dépend des données chargées via ajax, vous devez l'exécuter dans la méthode success. Placez le code dans une autre méthode, puis appelez cette méthode après les instructions eval.

<script type="text/javascript">
            function doSomeAmazingThings() {
                // amazing things go here
            }

            function loadViewViaAjax(url) {
                Ext.Ajax.request({
                    url: url,
                    success: function(objServerResponse) {
                        var responseText = objServerResponse.responseText;
                        var scripts, scriptsFinder=/<script[^>]*>([\s\S]+)<\/script>/gi;
                        while(scripts=scriptsFinder.exec(responseText)) {
                            eval.call(window,scripts[1]);
                        }
                        doSomeAmazingThings(); 
                        console.log('3. after loading ajax script');
                    }
                });
            }

            console.log('1. before loading ajax script');
            loadViewViaAjax('testEvalIssue_script.htm');
        </script>
3
Robby Pond

Pour cela, vous pouvez créer un objet XMLHttpRequest et appeler la fonction open avec le paramètre async défini sur false.

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "ajax_info.txt", false);
var response = xmlhttp.responseText;
1
Mahmood Khan

Vous pouvez essayer de rendre l'appel AJAX synchrone ... Bien sûr, vous devrez arrêter d'utiliser la bibliothèque Ext.Ajax, mais cela en vaut la peine si vous avez besoin de résultats ajax avant la prochaine ligne de code.

C'est ainsi que mes pages intranet communiquent avec ma base de données. J'ai découvert un inconvénient, en ce sens que vous ne pouvez voir aucune mise à jour de page tant que Javascript n'a pas abandonné le contrôle de la page. Par conséquent, des tâches telles qu'une barre d'état, une barre de progression ou une superposition sont impossibles avec Ajax synchrone (Cela n'est pas vrai pour mon firefox , il met à jour même dans le code synchrone dans certaines circonstances).

J'utilise ceci - c'est un peu maison et désordonné, mais cela a fonctionné sans faille pendant des années dans mon entourage. Créez simplement un nouvel AJAX (), définissez l'URL, ajoutez des requêtes (paires nom/valeur) selon vos besoins, définissez asynchrone sur false et, lorsque vous appelez Execute à partir d'une fonction, il se bloque jusqu'au retour d'Ajax.

Ou, si vous voulez l'utiliser de manière asynchrone, écrivez simplement une nouvelle fonction "déjà" pour l'objet AJAX que vous créez, et remplacez asynchrone par true.

J'ai écrit cela il y a de nombreuses années, alors ce n'est pas le meilleur choix et il existe des moyens de faire les choses différemment, mais cela fonctionne comme un amorce et vous pouvez le modifier comme bon vous semble sans avoir à dépendre d'une autre bibliothèque.

function AJAX(){

//Declarations
    var thisExt=this; //To be referenced by events

//Initialize Properties
    thisExt.URL="";
    thisExt.Query="";
    thisExt.Method="GET";
    thisExt.Asynchronous=true;
    thisExt.Encoding="application/x-www-form-urlencoded";
    thisExt.PostData="";

// Provide the XMLHttpRequest class for IE 5.x-6.x:
// Other browsers (including IE 7.x-8.x) ignore this
//   when XMLHttpRequest is predefined
if (typeof XMLHttpRequest == "undefined") {
    try { 
        thisExt.XMLHTTP = new ActiveXObject("Msxml2.XMLHTTP.6.0"); 
    }
    catch (e1) {
        try { thisExt.XMLHTTP = new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
        catch (e2) {
            try { thisExt.XMLHTTP = new ActiveXObject("Msxml2.XMLHTTP"); }
            catch (e3) {
                try { thisExt.XMLHTTP = new ActiveXObject("Microsoft.XMLHTTP"); }
                catch (e4) {
                    throw new Error("This browser does not support XMLHttpRequest.");
                }
            }
        }
    }
} else {
    thisExt.XMLHTTP = new XMLHttpRequest();
}


//Methods
    thisExt.XMLHTTP.onreadystatechange = function(){
        if(thisExt.XMLHTTP.readyState==4){
            window.status="";
            thisExt.onready(thisExt);//Passes thisExt so that the callback will have assess to the entire object, not just the returned text.
        }else{
            window.status=thisExt.XMLHTTP.readyState;//Just for debugging
        }
    }
    thisExt.addQuery=function(name,value){
        if(thisExt.Query!=""){
            thisExt.Query+="&"
        }
        thisExt.Query+=encodeURIComponent(name)+"="+encodeURIComponent(value)
    }

//Not really necessary, you could just say AjaxObj.URL="bla bla"
    thisExt.setURL=function(URL){
        thisExt.URL=URL;
    }
//Not really necessary, you could just say AjaxObj.Query="bla bla"
    thisExt.setQuery=function(Query){
        thisExt.Query=Query;
    }
//Not really necessary, you could just say AjaxObj.Method="bla bla"
    thisExt.setMethod=function(Method){
        thisExt.Method=Method;
    }
//Not really necessary, you could just say AjaxObj.Encoding="bla bla"
    thisExt.setEncoding=function(Encoding){
        thisExt.Encoding=Encoding;
    }
//Not really necessary, you could just say AjaxObj.PostData="bla bla"
    thisExt.setPostData=function(PostData){
        thisExt.PostData=PostData;
    }

    thisExt.Execute=function(){
        if(thisExt.URL==""){
            alert("AJAX.URL cannot be null.")
            return;
        }
        var URL2=thisExt.URL;
        if(thisExt.Query!=""){
            URL2=URL2+"?"+thisExt.Query;

        }
        if(thisExt.Method=="POST"){
            //this.XMLHTTP.setRequestHeader("Content-Type",this.Encoding);
            thisExt.XMLHTTP.open("POST", URL2, thisExt.Asynchronous);
            thisExt.XMLHTTP.send(thisExt.PostData);
        } else {
            thisExt.XMLHTTP.open("GET", URL2, thisExt.Asynchronous);
            thisExt.XMLHTTP.send(null);
        }
    }

//Events & callbacks
    thisExt.onready=function(){}
}
1
alfadog67