Comment faire pour que jQuery exécute 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 la fonction beforecreate . Il devrait retourner false pour empêcher un élément d'être créé.

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'élément, donc je devrais retourner false dans la fonction mère, pas dans le rappel. Est-il possible d'effectuer une synchrones Une requête AJAX utilisant jQuery ou une autre API de navigateur?

1071
demandé sur Artem Tikhomirov 2008-09-25 17:26:54

13 réponses

From the jQuery documentation : vous spécifiez l'option asynchrone à false pour obtenir une requête Ajax synchrone. Ensuite, votre callback peut définir quelques données avant que votre fonction mère ne démarre.

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
    });
}
1048
répondu Adam Bellaire 2015-11-21 12:20:02

vous pouvez mettre la configuration Ajax du jQuery en mode synchrone en appelant

jQuery.ajaxSetup({async:false});

et ensuite effectuer vos appels Ajax en utilisant jQuery.get( ... );

Then just turning it once again

jQuery.ajaxSetup({async:true});

je suppose que ça fonctionne comme suggéré par @Adam, mais ça pourrait être utile à quelqu'un qui veut reconfigurer leur syntaxe jQuery.get() ou jQuery.post() à la syntaxe plus élaborée jQuery.ajax() .

239
répondu Sydwell 2018-03-30 21:25:00

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 comme non définie. J'ai dû le stocker dans une variable et la retourner. C'est la méthode que j'ai trouvé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;
}
128
répondu James in Indy 2018-03-30 21:25:14

toutes ces réponses passent à côté du fait que faire un appel Ajax avec async:false provoquera la suspension du navigateur jusqu'à ce que la requête Ajax soit terminée. L'utilisation d'une bibliothèque de contrôle de flux résoudra ce problème sans raccrocher le navigateur. Voici un exemple avec le cadre .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
répondu BishopZ 2015-11-21 12:23:10
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


//example use
var msg=getURL("message.php");
alert(msg);
49
répondu Carcione 2012-04-25 15:34:38

gardez à l'esprit que si vous faites un appel Ajax inter-domaines (en utilisant JSONP ) - vous can't faites-le de façon synchrone, le drapeau async 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 nom de domaine et de faire le cross-domaine du serveur d'appel de côté
  2. changez votre code pour un fonctionnement asynchrone
  3. utilisez une bibliothèque" fonction sequencer " comme Frame.js ( réponse )
  4. bloque L'UI au lieu de bloquer l'exécution (cette réponse ) (ma voie préférée)
22
répondu Serge Shultz 2017-06-30 07:24:05

Note: vous ne devez pas utiliser async en raison de cela:

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

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

Synchrone XMLHttpRequest sur le thread principal est déconseillée en raison de son les effets néfastes de l'expérience de l'utilisateur final. Pour plus d'aide, consultez https://xhr.spec.whatwg.org / .

Cela pourrait briser votre page si vous faites quelque chose comme cela, car il pourrait arrêter de travailler toute la journée.

si vous voulez le faire d'une manière qui se sent encore comme si elle est synchrone mais ne bloque toujours pas, alors vous devriez utiliser async/Wait et probablement aussi un certain ajax qui est basé sur des promesses comme le nouveau Fetch API

async function foo() {
  var res = await fetch(url)
  console.log(res.ok)
  var json = await res.json()
  console.log(json)
}
19
répondu Endless 2017-12-13 20:04:51

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 j'ai changé le .responsabilité à responseJSON .

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

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

il y a deux aspects à considérer pour répondre à la question initiale. L'un dit à Ajax d'effectuer de manière synchrone (en définissant async: false ) et l'autre renvoie la réponse via le retour de la fonction d'appel, plutôt que dans une fonction de rappel.

j'ai aussi essayé avec POST et ça a marché.

j'ai changé le GET to 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;
}

noter que le code ci-dessus ne fonctionne que dans le cas où async est false . Si vous positionnez async: true l'objet retourné jqxhr ne serait pas valide au moment où L'appel AJAX retourne, ce n'est que plus tard lorsque l'appel asynchrone est terminé, mais c'est beaucoup trop tard pour définir la variable response .

10
répondu paulo62 2018-03-30 21:25:39

avec async: false vous obtenez vous-même 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 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 ASY are:

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
répondu Spen 2016-08-20 19:52:07

exemple:

$.ajax({
  url: "test.html",
  async: false
}).done(function(data) {
   // Todo something..
}).fail(function(xhr)  {
   // Todo something..
});
6
répondu searching9x 2014-08-16 13:20:10

tout d'abord, nous devrions comprendre quand nous utilisons $.ajax et quand nous utilisons $.obtenir.$/post

lorsque nous avons besoin d'un contrôle de bas niveau sur la requête ajax, comme les paramètres d'en-tête de requête, les paramètres de mise en cache, les paramètres synchrones, etc.alors vous devriez aller pour $.Ajax.

$.obtenir.$/post: quand nous n'avons pas besoin d'un contrôle de bas niveau sur la requête ajax.Il suffit d'obtenir/poster les données sur le serveur. c'est la abréviation de

$.ajax({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

et nous ne pouvons donc pas utiliser d'autres fonctionnalités(synchronisation,cache, etc.) avec.$ obtenir.$/post.

donc pour un contrôle de bas niveau(synchronisation,cache,etc.) sur demande ajax, nous devrions aller pour $.ajax

 $.ajax({
     type: 'GET',
      url: url,
      data: data,
      success: success,
      dataType: dataType,
      async:false
    });
2
répondu Sheo Dayal Singh 2017-10-03 09:52:59

c'est mon implémentation simple pour les requêtes asynchrones avec jQuery. J'espère que cela aide quelqu'un.

var queueUrlsForRemove = [
    'http://dev-myurl.com/image/1', 
    'http://dev-myurl.com/image/2',
    'http://dev-myurl.com/image/3',
];

var queueImagesDelete = function(){

    deleteImage( queueUrlsForRemove.splice(0,1), function(){
        if (queueUrlsForRemove.length > 0) {
            queueImagesDelete();
        }
    });

}

var deleteImage = function(url, callback) {
    $.ajax({
        url: url,
        method: 'DELETE'
    }).done(function(response){
        typeof(callback) == 'function' ? callback(response) : null;
    });
}

queueImagesDelete();
0
répondu Felipe Marques 2018-02-15 19:55:31

parce que XMLHttpReponse fonctionnement synchrone est déprécié j'ai trouvé la solution suivante qui enveloppe XMLHttpRequest . Cela permet des requêtes AJAX ordonnées tout en étant de nature asycnronous, ce qui est très utile pour les tokens CSRF à usage unique.

il est également transparent de sorte que les bibliothèques telles que jQuery fonctionneront de manière transparente.

/* wrap XMLHttpRequest for synchronous operation */
var XHRQueue = [];
var _XMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function()
{
  var xhr   = new _XMLHttpRequest();
  var _send = xhr.send;

  xhr.send = function()
  {
    /* queue the request, and if it's the first, process it */
    XHRQueue.push([this, arguments]);
    if (XHRQueue.length == 1)
      this.processQueue();
  };

  xhr.processQueue = function()
  {
    var call = XHRQueue[0];
    var xhr  = call[0];
    var args = call[1];

    /* you could also set a CSRF token header here */

    /* send the request */
    _send.apply(xhr, args);
  };

  xhr.addEventListener('load', function(e)
  {
    /* you could also retrieve a CSRF token header here */

    /* remove the completed request and if there is more, trigger the next */
    XHRQueue.shift();
    if (XHRQueue.length)
      this.processQueue();
  });

  return xhr;
};
0
répondu Geoffrey 2018-04-29 13:30:01