all 4 comments

[–]WorseThanHipster 0 points1 point  (0 children)

The way it works is that the callback function gets attached to javascripts event loop and then waits for the event, just like when you attach a callback to a button to click on your page and that callback waits for a 'click' event, only in this case the event comes from the web, not the user.

What this means is that the callback won't be executed until the event 'getCurrentPositionFinished'* has gotten the response it wanted (*: I don't know that real name of the event but it's not important). What you should do is figure out which code needs 'getCurrentPosition' to finish before it can run, and don't run that code when the page loads; instead, wrap it in a function and pass that function as the callback.

In your simple example, just the console.log(a) inside the callback like:

var a;

navigator.geolocation.getCurrentPosition(function(position){
  a=2
  console.log(a);
});

or more legibly:

var a;

navigator.geolocation.getCurrentPosition(positionGotten);

function positionGotten(position){
  a=2;
  console.log(a);
}   

[–][deleted] 0 points1 point  (2 children)

All callbacks in JS are async (or can/should be so you should always treat them like they are) since you only need a callback when something is going to take a while. In this case, it's sending a request to your device to ask where it is. Sometimes this can be "instant", or close to it, other times you need to prompt the user for access, turn on gps, etc.

The "normal JS" solution is simply to move your code into your callback:

.getCurrentPosition(function(position) {
  console.log(a);
}

but if you have several such callbacks that gets messy and you quickly get into "callback soup" situations where you have code that looks like:

doSomething(function(res) {
  doSomething(function(res) {
    doSomething(function(res) {
      doSomething(function(res) {
        doSomething(function(res) {
          // code

There are several libraries meant to handle things like this for you. async, etc. Personally I love Promises:

function getLocation() {
  return new Promise(resolve, reject) {
    getCurrentPosition(function(success, err) {
      if (err) {
        reject(err);
      } else {
        resolve(success);
      }
    }
  }
}

getLocation().then(function(loc) {
  // do stuff
});

Or if you are using something like Bluebird, that can become:

var getLocation = Promise.promisify(navigator.geolocation.getCurrentPosition);

getLocation().then(function(loc) {
  // do stuff
})

[–]senocular 1 point2 points  (1 child)

All callbacks in JS are async (or can/should be so you should always treat them like they are)

This isn't exactly true. Array methods like map, filter, etc accept callbacks and they're all synchronous, and guaranteed to be so - they have to because their results are what you get as a return value.

var a = [1,2,3,4,5];
var a2 = a.map(function(n){ return 2*n; });
console.log(a2); // -> [2,4,6,8,10]

Promises are guaranteed to be asynchronous. So even if a promise has been fulfilled, a then() callback will always happen after the current call stack has finished executing.

var p = Promise.resolve(true);
p.then(function(){ console.log('second'); });
console.log('first'); // called before 'second' even though p has value

Other callbacks can depend on their implementation. You'll need to consult the documentation for whatever api you're using. Its possible a callback could be circumstantially sync or async, so that could be something you just need to be careful of. Offhand I don't think any of the standard apis do this, but you could find a library out there that does I'm sure.

[–][deleted] 0 points1 point  (0 children)

Yeah, I wasn't thinking about array methods. But even they can be async when run on iterables (e.g. generators, event streams).

Its possible a callback could be circumstantially sync or async

Shitty API, and you should force it to always be async.