Pergunta

Eu tenho um widget JavaScript que fornece pontos de extensão padrão. Um deles é a função beforecreate. Ele deve retornar false para evitar um item que está sendo criado.

Eu adicionei uma chamada Ajax para esta função 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);
  });
}

Mas eu quero evitar que meu widget de criar o item, então eu deve retornar false na função mãe, não no retorno de chamada. Existe uma maneira de executar uma solicitação AJAX síncrona usando jQuery ou qualquer outro API no navegador?

Foi útil?

Solução

A partir da jQuery documentação : você especificar o assíncrona opção de ser false para obter uma solicitação do Ajax síncrona. Em seguida, o retorno de chamada pode definir alguns dados antes de sua função de rendimentos mãe.

Aqui está o que o código seria se mudou como sugerido:

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

Outras dicas

Você pode colocar configuração Ajax do jQuery no modo síncrono, chamando

jQuery.ajaxSetup({async:false});

E, em seguida, realizar o seu chamadas Ajax usando jQuery.get( ... );

Em seguida, basta ligá-lo novamente uma vez

jQuery.ajaxSetup({async:true});

Eu acho que ele funciona da mesma coisa como sugerido por @ Adam, mas pode ser útil para alguém que quer reconfigurar sua jQuery.get() ou jQuery.post() à sintaxe jQuery.ajax() mais elaborado.

Excelente solução! Eu observei quando eu tentei implementá-lo de que se eu voltasse um valor na cláusula de sucesso, ele voltou como indefinido. Eu tive que armazená-lo em uma variável e retornar essa variável. Este é o método que eu vim com:

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

Todas essas respostas perder o ponto que fazer uma chamada Ajax com async: false fará com que o navegador para pendurar até que os concluída requisição Ajax. Usando uma biblioteca de controle de fluxo vai resolver este problema sem desligar o navegador. Aqui está um exemplo com 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);

Tenha em mente que se você está fazendo um Ajax chamada cross-domain (usando JSONP ) - você < strong> não pode fazê-lo de forma síncrona, a bandeira async será ignorado pelo jQuery.

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

Para JSONP-chamadas que você poderia usar:

  1. Ajax-chamada para o seu próprio domínio - e fazer o server-side chamada cross-domain
  2. Altere o seu código para o trabalho de forma assíncrona
  3. Use uma "função sequenciador" biblioteca como Frame.js (este resposta )
  4. Bloquear a interface do usuário em vez de bloquear a execução (esta resposta ) (minha maneira favorita)

Nota: Você não deve usar async: false devido a este mensagens de aviso:

A partir do Gecko 30,0 (Firefox 30.0 / Thunderbird 30,0 / SeaMonkey 2.27), solicitações síncronas no segmento principal foram reprovados devido aos efeitos negativos para a experiência do usuário.

Chrome ainda adverte sobre isso no console:

Synchronous XMLHttpRequest no segmento principal é obsoleto por causa de seus efeitos nocivos para a experiência do usuário final. Para mais ajuda, consulte https://xhr.spec.whatwg.org/ .

Isso pode quebrar sua página se você está fazendo algo assim desde que ele poderia parar de trabalhar em qualquer dia.

Se você quiser fazê-lo de uma forma que ainda se sente como se é síncrona, mas ainda não bloqueiam então você deve usar async / await e provavelmente também alguns ajax que é baseado em promessas como o novo Obter API

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

Editar cromo está trabalhando em não permitindo sincronização XHR na página demissão quando a página está sendo navegado longe ou fechados por o usuário. Isso envolve beforeunload, descarregamento, pagehide e visibilitychange.

Se este é seu caso de uso, então você pode querer ter um olhar para navigator.sendBeacon vez

Também é possível que a página desativar req sincronia com http cabeçalhos ou do iframe permitir atributo

Com async: false você arranjar um navegador bloqueado. Para um não bloqueando solução síncrona você pode usar o seguinte:

ES6 / ECMAScript2015

Com ES6 você pode usar um gerador e a 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

Com ES7 você pode apenas usar asyc aguardam:

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

Eu usei a resposta dada por Carcione e modificou-lo para usar 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');
    }    
}

Eu adicionei o dataType de 'JSON' e mudou o .responseText para responseJSON .

Eu também recuperado o status usando o statusText propriedade do objeto retornado. Note, que este é o status da resposta do Ajax, não se o JSON é válido.

O back-end tem de voltar a resposta correcta em (bem formadas) JSON, caso contrário, o objecto devolvido será indefinido.

Existem dois aspectos a considerar ao responder a pergunta original. Um está dizendo Ajax para executar de forma síncrona (definindo async: false ). Eo outro está retornando a resposta via instrução de retorno da função de chamada, em vez de em uma função de retorno

Eu também tentei com POST e funcionou.

Eu mudei o GET para POST e acrescentou dados: 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;
}

Note que o código acima só funciona no caso em que assíncrono é false . Se você fosse set assíncrona: true o objeto retornado jqxhr não seria válido no momento da chamada Ajax retorna, só mais tarde, quando a chamada assíncrona foi concluída, mas que é muito tarde para definir o resposta variável.

Este é um exemplo:

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

Em primeiro lugar devemos entender quando usamos $ .ajax e quando usamos $ .get / $. Pós

Quando exigimos controle de baixo nível sobre o pedido ajax tais como definições de solicitação de cabeçalho, configurações de cache, configurações síncronos etc.then devemos ir para $ .ajax.

$ get / $ post:... Quando nós não requerem controle de baixo nível sobre o ajax request.Only simples GET / POST os dados para o servidor É abreviada de

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

e, portanto, não podemos usar outros recursos (sync, cache, etc.), com US $ .get / $. Post.

Por isso, para o controle de baixo nível (sync, cache, etc.) Ao longo de ajax solicitação, deve ir para $ .ajax

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

Esta é minha implementação simples para pedidos ASYNC com jQuery. Espero que isso ajuda ninguém.

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

Porque operação síncrona XMLHttpReponse está obsoleta eu vim com a seguinte solução que envolve XMLHttpRequest. Isso permite que ordenou consultas AJAX, enquanto continuam sendo asycnronous na natureza, o que é muito útil para uso único fichas CSRF.

Também é transparente assim bibliotecas como jQuery irá operar sem problemas.

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

Este é o meu “ Tópico ” namespace:

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

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

    }
};

E é assim que eu chamá-lo:

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

E se olhar para o console temos o seguinte resultado:

start 1:41:21 PM
end 1:41:31 PM
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top