How do I use jQuery promise/deffered in a custom function?

后端 未结 3 1241
太阳男子
太阳男子 2020-12-25 10:43

I have a function that gets the location through navigator.geolocation:

var getLocation = function( callback ){

    navigator.geolocation.getCu         


        
相关标签:
3条回答
  • Even though the above example did help me I had to do a bit more reading to wrap my head around the concept.

    Below is example based on my code that contains comments to assist me when I come back to it and hopefully anyone reading this Stackoverflow question:

    /* 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
          }
    );
    
    0 讨论(0)
  • 2020-12-25 11:28

    You have to instantiate a new deferred object and return it (or its promise) from the function. Call its .resolve method once you get the response:

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

    Usage:

    getLocation().then(drawMarkerOnMap);
    

    Reference: jQuery.Deferred


    Addendum:

    I would advise against using both approaches, deferred objects and passing callbacks to the function, to keep the interface simple. But if you have to stay backwards compatible, you can simply register the passed callback at the deferred object:

    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();
    };
    
    0 讨论(0)
  • 2020-12-25 11:28

    I know it says jQuery in the title but when I asked this question promises were new to the web and jQuery was the de facto library. Here's a more modern answer without jQuery.

    Use a native Promise

    All modern browsers (except for IE11 and below; use a polyfill if needed) enable you to use a native Promise construct.

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

    Usage:

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

    You can also use ES2016 async/await instead of .then():

    let runGetLocation = async () => {
    
      try {
        let position = await getLocation()
        console.log( position )
      } catch ( err ) { console.log( err ) }
    
    }
    
    0 讨论(0)
提交回复
热议问题