如何在自定义函数中使用jQuery promise / deffered?

我有一个通过navigator.geolocation获取位置的函数:

 var getLocation = function( callback ){ navigator.geolocation.getCurrentPosition( callback || function( position ){ // Stuff with geolocation }); }; 

我想这样做,以便我可以使用jQuerys的Deffered对象链接这个函数,但我仍然没有设法掌握Deffered的概念和用法。

我正在寻找类似于这个伪代码的东西:

 getLocation().then(function(){ drawMarkerOnMap(); }); 

这种语法是否可行,而不会在代码中向后翻转并淹没?

您必须实例化一个新的延迟对象并从该函数返回它(或它的promise)。 获得响应后调用其.resolve方法:

 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(); }; 

用法:

 getLocation().then(drawMarkerOnMap); 

参考jQuery.Deferred


附录

我建议不要使用两种方法,延迟对象和将回调传递给函数,以保持界面简单。 但是如果你必须保持向后兼容,你可以简单地在延迟对象上注册传递的回调:

 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(); }; 

尽管上面的例子确实对我有所帮助,但我还是要做更多的阅读来围绕这个概念。

下面是基于我的代码的示例,其中包含的注释可以帮助我回到它并希望有人阅读此Stackoverflow问题:

 /* 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 } ); 

我知道它在标题中说jQuery但是当我问这个问题时,promises对于web来说是新的,而jQuery是事实上的库。 这是没有jQuery的更现代的答案。

使用本机Promise

所有现代浏览器 (IE11及以下版本除外; 如果需要 , 使用polyfill )都可以使用本机Promise构造。

 let getLocation = () => { return new Promise( ( resolve, reject ) => { try { navigator.geolocation.getCurrentPosition( position => { resolve( position ) }) } catch ( err ) { reject( err ) } }) }; 

用法:

 let runGetLocation = () => { getLocation().then( position => console.log( position ) ) } 

您也可以使用ES2016 async / await而不是.then .then()

 let runGetLocation = async () => { try { let position = await getLocation() console.log( position ) } catch ( err ) { console.log( err ) } }