TL; DR: .done()
is the modern way of using success
, and it fulfills more or less (*) the specifications of a Promise. Which means it can be chained to the jQuery style and protects execution in case of errors.
Before the concept of Promises and deferred callbacks emerge the abitual method was to pass an object to the ajax method with the necessary settings. So the callback went into that object as well as the future code that depended on that response, which had to start from within the callback:
$.ajax({
url: url,
dataType: 'json',
type: 'GET',
success: function (_user){
fazerUpdateTabela(_user);
guardarUmCookie(_user);
procurarNoutraAPIqqCoisa(_user.nif, function(dadosPessoais){
verificarCartao(dadosPessoais.nrCartao, function(ver){
if (!ver) fazerTudoDeNovo();
// etc
});
});
// etc
}
});
In the case of eg procurarNoutraAPIqqCoisa
there was another step after it has completed the action chain becomes fragmented and after a few lines it is difficult to know the source and direction of executing the code.
Later, with the concept of Promises it is possible to write code that is a skeleton of what will happen and has a more visual and easy to perceive way. The above example could be adapted (with some internal settings in the functions) for this:
var ajax = $.ajax({
url: url,
dataType: 'json',
type: 'GET'
});
ajax
.done([guardarUmCookie, fazerUpdateTabela])
.done(procurarNoutraAPIqqCoisa.then(verificarCartao).fail(fazerTudoDeNovo));
*
- jQuery has had problems with jQuery deferreds threads. There is a bug / pr with a long discussion about it on Github . It seems that in version 3 this will be solved but in my view too late because browsers already allow a native version of the same idea.
The modern version is therefore more versatile and allows as I mentioned the chain of functions that should run when the response of the server arrives. It allows functions as argument but also function arrays, in the style of Promise.all
, which can be practical.
This version has an API parallel to the promises to forward these strings of .done()
and .fail(
'with several methods , giving you more flexibility to manage application flow.
Another important aspect of the Promises is that the errors generated within Promises do not wreak havoc like they used to. A "throw" within a Promise causes it and the following in the chain to be rejected and calls the .catch()
of the string. This is very useful for avoiding code that stops working.
After what I wrote above and returning to the question: Which one to use?
I'd rather use Promises and Ajax native. Nowadays this is already possible.
So the "normal" version with callbacks could be:
function _ajax(method, url, done) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
done(null, xhr.response);
};
xhr.onerror = function () {
done(xhr.response);
};
xhr.send();
}
// e para usar
_ajax('GET', 'http://example.com', function (err, dados) {
if (err) { console.log(err); }
else console.log('A resposta é:', dados);
});
The version with Promises could be thus an encapsulation of this old version, with powers Promise:
function ajax(method, url) {
return new Promise(function(resolve, reject) {
_ajax(method, url, function(err, res) {
if (err) reject(err);
else resolve(res);
});
});
}
or redo:
function _ajax(method, url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = resolve;
xhr.onerror = reject;
xhr.send();
});
}
and then use with:
ajax('GET', 'http://sopt.moon')
.then(function(dados) {
console.log(dados);
}).catch(function(err) {
console.error('Oh não!!', err.statusText);
});
With some more adaptations you can allow POST
, PUT,
etc. There is a complete polyfill in MDN for this.