javascript - example - jquery then vs done
¿Cómo uso jQuery promise/deffered en una función personalizada? (3)
Tengo una función que obtiene la ubicación a través de navigator.geolocation
:
var getLocation = function( callback ){
navigator.geolocation.getCurrentPosition( callback || function( position ){
// Stuff with geolocation
});
};
Me gustaría hacerlo para poder encadenar esta función utilizando el objeto Apfered de Deffered pero todavía no he logrado captar el concepto y el uso de Deffered.
Estoy buscando algo similar a este pseudo código :
getLocation().then(function(){
drawMarkerOnMap();
});
¿Es esta sintaxis incluso posible sin voltear hacia atrás y ahogarse en el código?
A pesar de que el ejemplo anterior me ayudó, tuve que leer un poco más para comprender el concepto.
A continuación se muestra un ejemplo basado en mi código que contiene comentarios que me ayudan cuando vuelvo y espero que cualquiera que lea esta pregunta de :
/* promise based getFilter to accommodate getting surrounding suburbs */
oSearchResult.fPromiseOfFilterSetting = function fPromiseOfFilterSetting(sId) {
var self = this;
self.oPromiseCache = self.oPromiseCache || {}; // creates a persistent cache
// across function calls
var oDeferred = $.Deferred(); // `new` keyword is optional
var oPromise = oDeferred.promise();
// leverage the cache (it''s ok if promise is still pending), you can key
if (self.oPromiseCache[sId] !== undefined) {
return self.oPromiseCache[sId];
}
else {
self.oPromiseCache[sId] = oPromise;
}
// do our asynchronous action below which at some point calls
// defered.resolve(...) and hence complete our promise
$.cmsRestProxy.doAjaxServiceRequest(''ocms_searchProperties_Extension'', {
action : ''getSurroundingSuburbs'',
sSuburbIds : ''a0RO0000003BwWeMAK''
}, function(result, json) {
console.log("doAjaxServiceRequest(
''ocms_searchProperties_Extension'')", json);
oDeferred.resolve(json); // `json` is our result and `.resolve(json)`
// passes the value as first argument to
// the `oPromise.done`, `oPromise.fail`
// and `oPromise.always` callback functions
})
// We can now return the promise or attach optional `oPromise.done`,
// `oPromise.fail`, and `oPromise.always` callbacks which will execute first
// in the chain.
//
// Note that `oPromise.then(doneCallback, failCallback, alwaysCallback)`
// is short form for the below
oPromise.done(function(value) { // returned by promise.resolve(...); call
console.log(''will run if this Promise is resolved.'', value);
})
oPromise.fail(function(value) {
console.log("will run if this Promise is rejected.", value);
});
oPromise.always(function(value) {
console.log("this will run either way.", value);
});
// return a promise instead of deferred object so that
// outside code cannot reject/resolve it
return oPromise;
}
// then to use one would do
oSearchResult.fPromiseOfFilterSetting().done(function(value) {alert(value)});
// or using $.when chaining
$.when(
oSearchResult.fPromiseOfFilterSetting()
)
.done(
function fDoneCallback(arg1, arg2, argN) {
console.debug(arguments) // `arguments` is an array of all args collected
}
);
Debe crear una instancia de un nuevo objeto diferido y devolverlo (o su promesa) desde la función. Llame a su método .resolve
una vez que obtenga la respuesta:
var getLocation = function() {
var deferred = new $.Deferred();
navigator.geolocation.getCurrentPosition(function( position ){
// Stuff with geolocation
deferred.resolve(position);
});
// return promise so that outside code cannot reject/resolve the deferred
return deferred.promise();
};
Uso:
getLocation().then(drawMarkerOnMap);
Referencia : jQuery.Deferred
Addendum :
Recomendaría no utilizar ambos enfoques, objetos diferidos y pasar devoluciones de llamada a la función, para mantener la interfaz simple. Pero si tiene que seguir siendo compatible con versiones anteriores, simplemente puede registrar la devolución de llamada pasada en el objeto diferido:
var getLocation = function(callback) {
var deferred = new $.Deferred();
if ($.isFunction(callback)) {
deferred.then(callback);
}
navigator.geolocation.getCurrentPosition(function( position ){
// Stuff with geolocation
deferred.resolve(position);
});
// return promise so that outside code cannot reject/resolve the deferred
return deferred.promise();
};
Sé que dice jQuery en el título, pero cuando hice esta pregunta, las promesas eran nuevas para la web y jQuery era la biblioteca de facto. Aquí hay una respuesta más moderna sin jQuery.
Usa una Promise
nativa
Todos los navegadores modernos (excepto IE11 y anteriores; use un polyfill si es necesario ) le permiten usar una construcción nativa Promise
.
let getLocation = () => { return new Promise( ( resolve, reject ) => { try { navigator.geolocation.getCurrentPosition( position => { resolve( position ) }) } catch ( err ) { reject( err ) } }) };
Uso:
let runGetLocation = () => { getLocation().then( position => console.log( position ) ) }
También puede usar ES2016 async / .then()
lugar de .then()
:
let runGetLocation = async () => { try { let position = await getLocation() console.log( position ) } catch ( err ) { console.log( err ) } }