Question Comment puis-je faire en sorte que jQuery effectue une requête Ajax synchrone plutôt qu'asynchrone?


J'ai un widget JavaScript qui fournit des points d'extension standard. L'un d'eux est le beforecreate fonction. Il devrait revenir false pour empêcher la création d'un élément.

J'ai ajouté un appel Ajax dans cette fonction en utilisant jQuery:

beforecreate: function (node, targetNode, type, to) {
  jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),

  function (result) {
    if (result.isOk == false) 
        alert(result.message);
  });
}

Mais je veux empêcher mon widget de créer l'objet, donc je devrais retourner false dans la fonction mère, pas dans le rappel. Existe-t-il un moyen d'effectuer une requête AJAX synchrone à l'aide de jQuery ou de toute autre API intégrée au navigateur?


1050
2017-09-25 13:26


origine


Réponses:


Du Documentation jQuery: vous spécifiez le asynchrone option d'être faux pour obtenir une requête Ajax synchrone. Ensuite, votre rappel peut définir certaines données avant que votre fonction mère ne se poursuive.

Voici à quoi ressemblerait votre code s'il était modifié comme suggéré:

beforecreate: function (node, targetNode, type, to) {
    jQuery.ajax({
        url: 'http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
        success: function (result) {
            if (result.isOk == false) alert(result.message);
        },
        async: false
    });
}

1032
2017-09-25 13:30



Vous pouvez mettre la configuration Ajax de jQuery en mode synchrone en appelant

jQuery.ajaxSetup({async:false});

Et puis effectuez vos appels Ajax en utilisant jQuery.get( ... );

Ensuite, il suffit de le rallumer une fois

jQuery.ajaxSetup({async:true});

Je suppose que cela fonctionne sur la même chose que suggéré par @ Adam, mais il pourrait être utile à quelqu'un qui veut reconfigurer leur jQuery.get() ou jQuery.post() à la plus élaborée jQuery.ajax() syntaxe.


237
2018-04-12 21:45



Excellente solution! J'ai remarqué quand j'ai essayé de l'implémenter que si je retournais une valeur dans la clause de succès, elle revenait indéfinie. Je devais le stocker dans une variable et retourner cette variable. C'est la méthode que j'ai inventée:

function getWhatever() {
  // strUrl is whatever URL you need to call
  var strUrl = "", strReturn = "";

  jQuery.ajax({
    url: strUrl,
    success: function(html) {
      strReturn = html;
    },
    async:false
  });

  return strReturn;
}

125
2018-04-07 13:30



Toutes ces réponses manquent le point qu'effectuer un appel Ajax avec async: false provoquera le blocage du navigateur jusqu'à la fin de la requête Ajax. L'utilisation d'une bibliothèque de contrôle de flux résoudra ce problème sans raccrocher le navigateur. Voici un exemple avec Frame.js:

beforecreate: function(node,targetNode,type,to) {

    Frame(function(next)){

        jQuery.get('http://example.com/catalog/create/', next);
    });

    Frame(function(next, response)){

        alert(response);
        next();
    });

    Frame.init();
}

82
2018-04-28 17:41



function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


//example use
var msg=getURL("message.php");
alert(msg);

49
2018-04-25 15:34



Gardez à l'esprit que si vous effectuez un appel Ajax inter-domaines (en utilisant JSONP) - toi ne peut pas faites-le de manière synchrone async Le drapeau sera ignoré par jQuery.

$.ajax({
    url: "testserver.php",
    dataType: 'jsonp', // jsonp
    async: false //IGNORED!!
});

Pour les appels JSONP, vous pouvez utiliser:

  1. Ajax-appel à votre propre domaine - et faire le côté serveur d'appel inter-domaine
  2. Changez votre code pour travailler de manière asynchrone
  3. Utilisez une bibliothèque de "séquenceur de fonctions" comme Frame.js (cette répondre)
  4. Bloquer l'interface utilisateur au lieu de bloquer l'exécution (cette répondre) (ma façon préférée)

22
2018-05-10 06:28



Note: Vous ne devriez pas utiliser async à cause de ceci:

À partir de Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), les requêtes synchrones sur le thread principal ont été abandonnées en raison des effets négatifs sur l'expérience utilisateur.

Chrome avertit même à ce sujet dans la console:

XMLHttpRequest synchrone sur le thread principal est obsolète en raison de ses effets préjudiciables à l'expérience de l'utilisateur final. Pour plus d'aide, vérifiez https://xhr.spec.whatwg.org/.

Cela pourrait casser votre page si vous faites quelque chose comme ça, car il pourrait cesser de fonctionner n'importe quel jour.

Si vous voulez le faire de façon à ce qu'il soit toujours synchrone mais ne bloque pas, vous devriez utiliser async / await et probablement aussi un ajax basé sur des promesses comme le nouveau Chercher API

async function foo() {
  var res = await fetch(url)
  console.log(res.ok)
  var json = await res.json()
  console.log(json)
}

17
2017-12-13 12:55



Avec async: false vous obtenez un navigateur bloqué. Pour une solution synchrone non bloquante, vous pouvez utiliser ce qui suit:

ES6 / ECMAScript2015

Avec ES6, vous pouvez utiliser un générateur et le bibliothèque de co:

beforecreate: function (node, targetNode, type, to) {
    co(function*(){  
        let result = yield jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
        //Just use the result here
    });
}

ES7

Avec ES7, vous pouvez simplement utiliser asyc await:

beforecreate: function (node, targetNode, type, to) {
    (async function(){
        let result = await jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
        //Just use the result here
    })(); 
}

9
2017-08-20 19:52



J'ai utilisé la réponse donnée par Carcione et l'ai modifiée pour utiliser JSON.

 function getUrlJsonSync(url){

    var jqxhr = $.ajax({
        type: "GET",
        url: url,
        dataType: 'json',
        cache: false,
        async: false
    });

    // 'async' has to be 'false' for this to work
    var response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};

    return response;
}    

function testGetUrlJsonSync()
{
    var reply = getUrlJsonSync("myurl");

    if (reply.valid == 'OK')
    {
        console.dir(reply.data);
    }
    else
    {
        alert('not valid');
    }    
}

J'ai ajouté le Type de données de 'JSON' et a changé le .responseText à responseJSON.

J'ai également récupéré le statut en utilisant le statusText propriété de l'objet retourné. Notez que c'est le statut de la réponse Ajax, pas si le JSON est valide.

Le back-end doit retourner la réponse dans le JSON correct (bien formé), sinon l'objet retourné sera indéfini.

Il y a deux aspects à considérer en répondant à la question originale. On dit à Ajax d'effectuer de manière synchrone async: false) et l'autre renvoie la réponse via l'instruction return de la fonction appelante, plutôt que dans une fonction de rappel.

J'ai aussi essayé avec POST et cela a fonctionné.

J'ai changé le GET à POST et ajouté données: postdata

function postUrlJsonSync(url, postdata){

    var jqxhr = $.ajax({
        type: "POST",
        url: url,
        data: postdata,
        dataType: 'json',
        cache: false,
        async: false
    });

    // 'async' has to be 'false' for this to work
    var response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};

    return response;
}

Notez que le code ci-dessus ne fonctionne que dans le cas où async est faux. Si vous deviez définir async: true l'objet retourné jqxhr ne serait pas valide au moment du retour de l'appel AJAX, mais seulement plus tard lorsque l'appel asynchrone sera terminé, mais il est beaucoup trop tard pour régler le réponse variable.


8
2017-11-15 11:33