Domanda

Ho un widget JavaScript che fornisce punti di estensione standard. Uno di questi è la funzione beforecreate . Dovrebbe restituire false per impedire la creazione di un elemento.

Ho aggiunto una chiamata Ajax in questa funzione usando 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);
  });
}

Ma voglio impedire al mio widget di creare l'elemento, quindi dovrei restituire false nella funzione madre, non nel callback. Esiste un modo per eseguire una richiesta AJAX sincrona utilizzando jQuery o qualsiasi altra API nel browser?

È stato utile?

Soluzione

Dalla documentazione jQuery : specifichi il asincrono opzione per essere false per ottenere una richiesta Ajax sincrona. Quindi il callback può impostare alcuni dati prima che la funzione madre proceda.

Ecco come sarebbe il tuo codice se modificato come suggerito:

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

Altri suggerimenti

Puoi mettere la configurazione Ajax di jQuery in modalità sincrona chiamando

jQuery.ajaxSetup({async:false});

E poi esegui le tue chiamate Ajax usando jQuery.get (...);

Quindi riaccenderlo una volta

jQuery.ajaxSetup({async:true});

Suppongo che funzioni come suggerito da @Adam, ma potrebbe essere utile a qualcuno che vuole riconfigurare il loro jQuery.get () o jQuery.post ( ) nella sintassi jQuery.ajax () più elaborata.

Ottima soluzione! Quando ho provato a implementarlo ho notato che se restituissi un valore nella clausola success, sarebbe tornato come indefinito. Ho dovuto memorizzarlo in una variabile e restituire quella variabile. Questo è il metodo che mi è venuto in mente:

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;
}

Tutte queste risposte mancano il punto che fare una chiamata Ajax con asincrono: false causerà il blocco del browser fino al completamento della richiesta Ajax. L'uso di una libreria di controllo del flusso risolverà questo problema senza riagganciare il browser. Ecco un esempio con 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();
}
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


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

Tieni presente che se stai effettuando una chiamata Ajax tra domini (utilizzando JSONP ) - tu < strong> impossibile farlo in modo sincrono, il flag async verrà ignorato da jQuery.

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

Per le chiamate JSONP è possibile utilizzare:

  1. Ajax-call al tuo dominio - ed esegui la chiamata cross-domain lato server
  2. Modifica il codice in modo che funzioni in modo asincrono
  3. Utilizza un sequencer di funzioni " " libreria come Frame.js (questa risposta )
  4. Blocca l'interfaccia utente invece di bloccare l'esecuzione (questa rispondi ) (il mio modo preferito)

Nota: non utilizzare async: false a causa di questi messaggi di avviso:

  

A partire da Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), le richieste sincrone sul thread principale sono state deprecate a causa degli effetti negativi sull'esperienza utente.

Chrome lo avvisa persino nella console:

  

XMLHttpRequest sincrono sul thread principale è obsoleto a causa dei suoi effetti dannosi per l'esperienza dell'utente finale. Per ulteriori informazioni, consulta https://xhr.spec.whatwg.org/ .

Questo potrebbe spezzare la tua pagina se stai facendo qualcosa del genere poiché potrebbe smettere di funzionare ogni giorno.

Se vuoi farlo in un modo che sembra ancora sincrono ma che non si blocca, dovresti usare async / wait e probabilmente anche qualche ajax che si basa su promesse come il nuovo Fetch API

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

Modifica chrome sta lavorando su Non consentire la sincronizzazione di XHR nel licenziamento della pagina quando la pagina viene spostata via o chiusa da l'utente. Ciò comporta lo scaricamento anticipato, lo scaricamento, il pagehide e il cambio di visibilità.

se questo è il tuo caso d'uso, potresti dare un'occhiata a navigator.sendBeacon invece

È anche possibile per la pagina disabilitare la sincronizzazione req con le intestazioni http o l'attributo allow iframe

Con async: false ottieni un browser bloccato. Per una soluzione sincrona non bloccante è possibile utilizzare quanto segue:

ES6 / ECMAScript2015

Con ES6 puoi usare un generatore e un amplificatore; la co-biblioteca :

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

Con ES7 puoi semplicemente usare asyc waitit:

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

Ho usato la risposta data da Carcione e l'ho modificata per usare 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');
    }    
}

Ho aggiunto il tipo di dati di 'JSON' e ho modificato il .responseText in responseJSON .

Ho anche recuperato lo stato usando la proprietà statusText dell'oggetto restituito. Si noti che questo è lo stato della risposta Ajax, non se JSON è valido.

Il back-end deve restituire la risposta nel JSON corretto (ben formato), altrimenti l'oggetto restituito non sarà definito.

Ci sono due aspetti da considerare quando si risponde alla domanda originale. Uno sta dicendo ad Ajax di eseguire in modo sincrono (impostando asincrono: falso ) e l'altro sta restituendo la risposta tramite l'istruzione return della funzione chiamante, piuttosto che in una funzione callback.

L'ho provato anche con POST e ha funzionato.

Ho cambiato GET in POST e ho aggiunto dati: 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;
}

Nota che il codice sopra riportato funziona solo nel caso in cui asincrono sia falso . Se dovessi impostare asincrono: vero l'oggetto restituito jqxhr non sarebbe valido al momento della restituzione della chiamata AJAX, solo in seguito al termine della chiamata asincrona, ma è troppo tardi per impostare la risposta variabile.

Questo è un esempio:

$.ajax({
  url: "test.html",
  async: false
}).done(function(data) {
   // Todo something..
}).fail(function(xhr)  {
   // Todo something..
});

In primo luogo dovremmo capire quando usiamo $ .ajax e quando usiamo $ .get / $. post

Quando abbiamo bisogno di un controllo di basso livello sulla richiesta ajax come le impostazioni dell'intestazione della richiesta, le impostazioni di memorizzazione nella cache, le impostazioni sincrone ecc., allora dovremmo scegliere $ .ajax.

$ .get / $. post: quando non richiediamo un controllo di basso livello sulla richiesta ajax. È sufficiente ottenere / pubblicare i dati sul server. È una scorciatoia di

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

e quindi non possiamo usare altre funzionalità (sincronizzazione, cache ecc.) con $ .get / $. post.

Quindi per un controllo di basso livello (sincronizzazione, cache, ecc.) su una richiesta Ajax, dovremmo scegliere $ .ajax

 $.ajax({
     type: 'GET',
      url: url,
      data: data,
      success: success,
      dataType: dataType,
      async:false
    });

questa è la mia semplice implementazione per richieste ASYNC con jQuery. Spero che questo aiuti chiunque.

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

Poiché l'operazione sincrona XMLHttpReponse è obsoleta, ho trovato la seguente soluzione che racchiude XMLHttpRequest . Ciò consente query AJAX ordinate pur essendo di natura asincrona, il che è molto utile per i token CSRF monouso.

È anche trasparente, quindi librerie come jQuery funzioneranno senza problemi.

/* 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;
};

Questo è il mio & # 8220; Discussione & # 8221; namespace:

var Thread = {
    sleep: function(ms) {
        var start = Date.now();

        while (true) {
            var clock = (Date.now() - start);
            if (clock >= ms) break;
        }

    }
};

Ed è così che lo chiamo:

var d1 = new Date();
console.log('start ' + d1.toLocaleTimeString());
Thread.sleep(10000);
var d2 = new Date();
console.log('end ' + d2.toLocaleTimeString());

E guardando la console si ottiene il seguente risultato:

start 1:41:21 PM
end 1:41:31 PM
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top