I'm very new to Promises, deferred and all that kind of thing and I'm trying to change my old habits (callbacks hell) to Promises, using jQuery (I know it doesn't respect Promise A+, but that's not the point).
What I've done now is a mix of both, and I'm trying to get rid of the callbacks. I'm also using TypeScript, but it shouldn't be related as far as I know. I am just giving fair warning that the code is not pure JS.
// TODO I provide the "done" and "fail" callback here, but I'd like to use .done and .fail instead, but I want them to be executed AFTER the automatic response handling.
WidgetContext.getContext(
function(data){
console.log(data)
},
function(error){
console.log(error)
}
);
// In WidgetContext class, TODO here I want to get rid of the callbacks as well.
public static getContext(done: any, fail: any): JQueryPromise<WidgetContext> {
return Payline.WebService.WidgetWSProxy.ajax(
'context1.json',
{
userId: 123456
},
done,
fail
);
}
// In WidgetWSProxy class, TODO here again, there should not be any callback.
public static ajax(method: string = '', data: any = {}, done?: any, fail?: any, options: JQueryAjaxSettings = WidgetWSProxy._defaultOptions): JQueryPromise<WidgetWSProxy>{
var url = WidgetWSProxy.buildUrl(WidgetWSProxy._url, method);
return WidgetWSProxy._ajax(url, data, done, fail, WidgetWSProxy._processAjaxResponseData, WidgetWSProxy._logId + ' ' + url, options);
}
// In AbstractHttpProxy class, TODO the only callback should be the responseHandler.
protected static _ajax(url: string, data: any, done?: any, fail?: any, responseHandler?: any, logId: string = AbstractHttpProxy._logId, options: JQueryAjaxSettings = AbstractHttpProxy._defaultOptions): JQueryPromise<AbstractHttpProxy>{
// On log la requête.
log.group(logId);
log.time(logId);
// Si aucun gestionnaire de réponse n'est correctement fourni, utilisation de celui par défaut.
if(!_.isFunction(responseHandler)){
responseHandler = AbstractHttpProxy._defaultResponseHandler;
}
// On injecte les data dans les options, on fait ainsi afin de cacher la logique jQuery pour ce paramètre particulier qui sera souvent utilisé.
options = _.merge(options, {data: data});
log.info('Requête HTTP envoyée: ' + JSON.stringify({
url: url,
options: options
}));
// On effectue l'appel ajax et on retourne une Promise jQuery.
return $.ajax(url, options)
// Succès
.done(function(data){
if(_.isFunction(done)){
responseHandler(url, data, true, function(data){
// TODO HERE I execute the "done" callback inside the done() function, but I should not. I just need to call the responseHandler and update the data so the next call to ".done()" would use the updated data, even though I define it when I call the "WidgetContext.getContext()" method.
done(data);
});
}else{
logMissingCallback(getCallerName());
}
})
// Erreur (connexion interrompue, 404, 500, peu importe)
.fail(function(error){
if(_.isFunction(fail)){
responseHandler(url, error, false, function(error){
// TODO Same stuff here, with the fail().
fail(error);
});
}else{
logMissingCallback(getCallerName());
}
})
// Sera toujours exécuté, peu importe ce qu'il se passe. (succès/erreur)
.always(function(){
log.timeEnd(logId);
log.groupEnd();
}
);
}
My aim is to hide some logic behind the use of a proxy (WidgetWSProxy), to automatically log all requests and also handle HTTP responses to format them as I want, then use the transformed response using .done
deferred function.
It works here, but if I do something like this, it doesn't log the updated response in the .done
call.
WidgetContext.getContext(
function(data){
console.log(data)
},
function(error){
console.log(error)
}
)
.done(function(data){
console.log('init')
console.log(data)
});
It's hard to get rid of the callback hell way to think when you've used it for years... Thanks for the help!