Manipulação de jQuery.ajax continue respostas: "success:" vs ".done"?

309

Trabalho com jQuery e AJAX há algumas semanas e vi duas maneiras diferentes de 'continuar' o script depois que a chamada foi feita: success:e .done.

A partir da sinopse da documentação do jQuery , obtemos:

.done (): Descrição: adicione manipuladores a serem chamados quando o objeto Adiado for resolvido.

success: (opção .ajax ()): uma função a ser chamada se a solicitação for bem-sucedida.

Portanto, ambos fazem algo depois que a chamada AJAX foi concluída / resolvida. Posso usar um ou outro aleatoriamente? Qual é a diferença e quando um é usado em vez do outro?

Claudio
fonte

Respostas:

469

successfoi o nome tradicional do retorno de chamada bem-sucedido no jQuery, definido como uma opção na chamada ajax. No entanto, desde a implementação de $.Deferredsretornos de chamada mais sofisticados, doneé a maneira preferida de implementar retornos de sucesso, como pode ser chamado em qualquer deferred.

Por exemplo, sucesso:

$.ajax({
  url: '/',
  success: function(data) {}
});

Por exemplo, feito:

$.ajax({url: '/'}).done(function(data) {});

O ponto positivo doneé que o valor de retorno $.ajaxagora é uma promessa adiada que pode ser vinculada a qualquer outro lugar no seu aplicativo. Então, digamos que você queira fazer essa chamada ajax de alguns lugares diferentes. Ao invés de passar em sua função de sucesso como uma opção para a função que faz com que esta chamada ajax, você pode apenas ter a função de retorno $.ajaxem si e ligam seus retornos de chamada com done, fail, then, ou o que quer. Observe que alwaysé um retorno de chamada que será executado se a solicitação for bem-sucedida ou falhar. donesó será acionado com sucesso.

Por exemplo:

function xhr_get(url) {

  return $.ajax({
    url: url,
    type: 'get',
    dataType: 'json',
    beforeSend: showLoadingImgFn
  })
  .always(function() {
    // remove loading image maybe
  })
  .fail(function() {
    // handle request failures
  });

}

xhr_get('/index').done(function(data) {
  // do stuff with index data
});

xhr_get('/id').done(function(data) {
  // do stuff with id data
});

Um benefício importante disso em termos de manutenção é que você envolveu seu mecanismo ajax em uma função específica do aplicativo. Se você decidir que sua $.ajaxchamada funcionará de maneira diferente no futuro, ou se usar um método ajax diferente ou se afastar do jQuery, precisará alterar apenas a xhr_getdefinição (não se esqueça de retornar uma promessa ou pelo menos um donemétodo, em o caso do exemplo acima). Todas as outras referências em todo o aplicativo podem permanecer as mesmas.

Você pode fazer muito mais coisas (muito mais legais) $.Deferred, uma das quais é usar pipepara acionar uma falha em um erro relatado pelo servidor, mesmo quando a $.ajaxsolicitação é bem-sucedida. Por exemplo:

function xhr_get(url) {

  return $.ajax({
    url: url,
    type: 'get',
    dataType: 'json'
  })
  .pipe(function(data) {
    return data.responseCode != 200 ?
      $.Deferred().reject( data ) :
      data;
  })
  .fail(function(data) {
    if ( data.responseCode )
      console.log( data.responseCode );
  });
}

xhr_get('/index').done(function(data) {
  // will not run if json returned from ajax has responseCode other than 200
});

Leia mais $.Deferredaqui: http://api.jquery.com/category/deferred-object/

NOTA : A partir do jQuery 1.8, pipefoi preterido em favor do uso thenexatamente da mesma maneira.

glortho
fonte
2
Eu me pergunto como as interações de success:/ .done()são definidas, se é que existem. Por exemplo, é success:apenas implementado como o primeiro .done()nos dias de hoje?
6
Quer dizer, se você tem os dois success:e .doneem uma chamada ajax? Boa pergunta. Como todos os outros retornos de chamada são chamados na ordem em que estão vinculados, meu palpite é que sim, successé apenas chamado primeiro.
glOrtho
1
Muito bom post! Btw, no retorno de chamada do canal, você não deveria estar chamando a função de canal com o parâmetro jqXHR para verificar a resposta do status? Ex: .pipe (function (data, textStatus, jqXHR) {if (jqXHR.status == 200) {...
Eder
@Eder O cenário que estou abordando com esse uso de pipeé aquele em que a solicitação é bem-sucedida, mas o script no servidor não retornou o que você estava procurando. Você pode não querer lançar 404 ou 500 reais ou o que quer que seja no lado do servidor, porque deseja distinguir significativamente entre respostas http e respostas de aplicativos. Definir um código de resposta no JSON e, em seguida, usá-lo pipedessa maneira permite lidar com diferentes tipos de erros com mais nuances.
glortho 12/05
Outro benefício importante do uso de promessas é que seu código se torna muito mais legível e você evita o "inferno de retorno de chamada". Isso é especialmente verdadeiro quando você tem vários retornos de chamada que deseja executar cada um após a conclusão anterior. Com promessas, pareceria com myPromiseCall.then (..). Then (..) em vez de uma estrutura complicada aninhada de retornos de chamada usados ​​com a opção success.
BornToCode
5

Se você precisar async: falseno seu ajax, use em successvez de .done. Caso contrário, é melhor você usar .done. Isto é do site oficial do jQuery :

A partir do jQuery 1.8, o uso de async: false com jqXHR ($ .Deferred) está obsoleto; você deve usar as opções de retorno de chamada com êxito / erro / concluir , em vez dos métodos correspondentes do objeto jqXHR, como jqXHR.done () .

AmirHossein Manian
fonte
Quem mencionou async:false?
Liam
$.ajax({ url: req_url, ..., async: false, success: function (result, status, req) { }, error: function (jqXHR, status) { } });
AmirHossein Manian
0

Da documentação do JQuery

Os objetos jqXHR retornados pelo $.ajax()jQuery 1.5 implementam a interface Promise, fornecendo a eles todas as propriedades, métodos e comportamento de uma Promise (consulte Objeto adiado para obter mais informações). Esses métodos usam um ou mais argumentos de função que são chamados quando a $.ajax()solicitação termina. Isso permite atribuir vários retornos de chamada em uma única solicitação e até atribuir retornos de chamada após a conclusão da solicitação. (Se a solicitação já estiver concluída, o retorno de chamada será acionado imediatamente.) Os métodos Promise disponíveis do objeto jqXHR incluem:

jqXHR.done(function( data, textStatus, jqXHR ) {});

Uma construção alternativa à opção de retorno de chamada bem-sucedida, consulte os deferred.done()detalhes da implementação.

jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {});

Uma construção alternativa à opção de retorno de chamada de erro, o .fail()método substitui o método .error () descontinuado. Consulte deferred.fail () para obter detalhes da implementação.

jqXHR.always(function( data|jqXHR, textStatus, jqXHR|errorThrown ) { }); 

(adicionado no jQuery 1.6) Uma construção alternativa à opção de retorno de chamada completa, o .always()método substitui o .complete()método obsoleto .

Em resposta a uma solicitação bem-sucedida, os argumentos da função são os mesmos de .done(): data, textStatus e o objeto jqXHR. Para pedidos com falha, os argumentos são os mesmos de .fail(): o objeto jqXHR, textStatus e errorThrown. Consulte os deferred.always()detalhes da implementação.

jqXHR.then(function( data, textStatus, jqXHR ) {}, function( jqXHR, textStatus, errorThrown ) {});

Incorpora a funcionalidade dos métodos .done()e .fail(), permitindo (a partir do jQuery 1.8) a promessa subjacente ser manipulada. Consulte adiado .then()para obter detalhes da implementação.

Deprecation Aviso: O jqXHR.success(), jqXHR.error()e jqXHR.complete()chamadas de retorno são removidos a partir de jQuery 3.0. Você pode usar jqXHR.done(), jqXHR.fail()e, jqXHR.always()em seu lugar.

Sasmit
fonte