TL;DR: the .done()
is the modern way of using the success
, and meets 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 emerged the usual method was to pass an object to the ajax method with the necessary settings. So the callback went on this object as well as the future code that depended on that answer, which had to start from inside 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 for example procurarNoutraAPIqqCoisa
had there been another step to follow after that to have completed the chain of actions is fragmented and passed some lines it is already difficult to know the origin and direction of execution of 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 path. The above example could be adapted (with some internal adjustments in functions) to 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 linkages. 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 the browsers already allow a native version of the same idea.
The modern version is therefore more versatile and allows as I mentioned the chaining of functions that should run when the server response arrives. Allows functions as argument but also function arrays, like the Promise.all
, what can be practical.
This version has an API parallel to the files to forward these strings to .done()
and .fail(
)` with various methods, giving more flexibility to manage the application flow.
Another important aspect of Promises is that the errors generated within Promises don’t do the same damage as before. An error ('throw') inside a Promise causes it and the following of the string to be rejected and calls the .catch()
chain. This is very useful to avoid crashing code.
After what I wrote above and returning to the question: Which to use?
I prefer to use Promises and native Ajax. 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 thus be an encapsulation of this old version with Promise powers:
function ajax(method, url) {
return new Promise(function(resolve, reject) {
_ajax(method, url, function(err, res) {
if (err) reject(err);
else resolve(res);
});
});
}
or remaking:
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 a few more adaptations may allow POST
, PUT,
etc. There is a full polyfill on MDN for this.
The answer is not used but some explanation follows: http://stackoverflow.com/questions/14754619/jquery-ajax-success-callback-function-definition/14754681#14754681
– Guerra
@War I had already read this answer, and it is excellent. I even thought about getting into the merit of
resolve
in my question, but I think this is worth a completely different question. Anyway, good reference =)– Caio Felipe Pereira
I don’t know a case that has to specifically use one of them. And I think the use of Promisses, the
done()
, facilitates code reading and brings the language closer to OO.– Leonardo Leal
@Leonardoleal, I agree. The approach to the OO, even more now with the ES6 turning the corner, I like it a lot, outside that it is possible to separate the responsibilities of capture and manipulation of the data, in this case in particular
– Caio Felipe Pereira