rutruth
rutruth

Reputation: 790

Create async function in Javascript

I have this module that wraps a call to an asynchronous method to watch for changes in the browser's geolocation navigator.geolocation.watchPosition

var geo_value;

//Initialises the devices geolocation
navigator.geolocation.watchPosition(function (position) {
    geo_value = position.coords.longitude + "," + position.coords.latitude;
});

Everytime the watchPosition method call fires, I store the value in a variable to provide me programmatic access to the currentPosition at any given time.

This all works fine, however I now want to expose this currentPosition via a custom async method that I am exporting from my module.

define(["global"], function (window) {

   var navigator = window.navigator;

   var geo_value;

   //Initialises the devices geolocation
   navigator.geolocation.watchPosition(function (position) {
       geo_value = position.coords.longitude + "," + position.coords.latitude;
   });


   return {
       currentPosition: function (callback) {
           setTimeout(function () {
               while (!geo_value) {
                   //keep looping until geo_value has been initially set by the watch position above
               }
               //geo_value has been set, execute callback
               callback(geo_value);
           }, 0);

       }
   };
});

I have made the module expose the currentPosition, which works if geo_value has already been set, but I also want it to wait asynchronously if geo_value hasn't been set and then execute the callback when the watchPosition finally sets a value for geo_value. I tried using the setTimeout function to attempt at making it asynchronous, but it didn't work.

Please any help will be much appreciated.

Upvotes: 0

Views: 6538

Answers (3)

Tamas
Tamas

Reputation: 3442

This code below blocks other code to be executed as JavaScript only has one thread of execution:

while (!geo_value) {
    //keep looping until geo_value has been initially set by the watch position above
}

Instead try something like this:

currentPosition: function(callback) {
  if (geo_value) {
    callback(geo_value);
  } else {
    // try again 1 sec later
    setTimeout(this.currentPosition.bind(this, callback), 1000);
  }
}

Upvotes: 0

Kenan Banks
Kenan Banks

Reputation: 211942

So, Javascript is really a single-threaded event loop. Getting a feel for what exactly that means will take experience.

In this case, it means that your while loop will never terminate, because nothing else can happen while it's running.

One better way to do this is to call the callbacks you're getting as params to currentPosition when watchPosition is called.

define(["global"], function (window) {

   var navigator = window.navigator,
       geo_value,
       callbacks = [],


   //Initialises the devices geolocation
   navigator.geolocation.watchPosition(function (position) {
       geo_value = position.coords.longitude + "," + position.coords.latitude;

       // Update all callbacks with new value. 
       for (var i = 0; i < callbacks.length; i++) {
           callbacks[i](geo_value);
       }
   });


   return {
       onCurrentPosition: function (callback) {
           callbacks.push(callback)
       }
   };
});

Upvotes: 2

closure
closure

Reputation: 7452

define(["global"], function (window) {

   var navigator = window.navigator;

   var geo_value;
   var cb;

   //Initialises the devices geolocation
   navigator.geolocation.watchPosition(function (position) {
       geo_value = position.coords.longitude + "," + position.coords.latitude;
       if (cb) {
         cb(geo_value);
         cb = null;
       }
   });


   return {
       currentPosition: function (callback) {
        if (geo_value) {
            callback(geo_value);
        } else {
            cb = callback;
        }
   };
});

Upvotes: 1

Related Questions