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