16

I'm experiencing a problem of $.get function. The url contains JSON

my code:

 xyz = null

    $.get('http://www.someurl.com/123=json', function(data) {
       var xyz = data.positions[0].latitude;
    });

alert(xyz);
//some more code using xyz variable

I know that xyz will alert a null result because the $.get is asynchronous.

So is there any way I can use the xyz outside this get function?

thecodeparadox
  • 86,271
  • 21
  • 138
  • 164
Diolor
  • 13,181
  • 30
  • 111
  • 179
  • If you move the `var` keyword out of your function and in front of your initial `xyz` then you can use it anywhere in that scope in any function that executes after your ajax request completes. – Paul Jun 10 '12 at 22:39
  • 4
    While there *is* **synchronous** AJAX (it's *documented* in jQuery), it should usually *be avoided* because of the negative impact it has on the user experience. Instead, focus on using the event-based model of asynchronous AJAX. That is, update the DOM with `xyz` *from within* the callback. –  Jun 10 '12 at 22:44
  • @pst. Same question all the time. This one and the DOM ready problem. – gdoron Jun 10 '12 at 22:46
  • @gdoron Nope, not the "DOM ready", the "return variable from AJAX get" ;-) Lemme get some dupes... –  Jun 10 '12 at 22:48
  • 2
    http://stackoverflow.com/questions/9973681/jquery-how-to-use-the-return-value-of-an-ajax-call-outside-that-ajax-call?lq=1 , http://stackoverflow.com/questions/3375046/jquery-ajax-call-return-value-problem?rq=1 , http://stackoverflow.com/questions/9483921/cant-set-an-variable-in-jquery-getjson-function?rq=1 , http://stackoverflow.com/questions/8633051/jquery-ajax-get-result , http://stackoverflow.com/questions/4546339/jquery-assign-json-as-a-result-to-a-variable –  Jun 10 '12 at 22:49
  • @pst. Nice list you got over there... :) – gdoron Jun 10 '12 at 22:55

3 Answers3

23

get is a shortcut. You can do the same, but synchronous, using:

var xyz = null


$.ajax({ url: 'http://www.someurl.com/123=json', 
         async: false,
         dataType: 'json',
         success: function(data) {
              xyz = data.positions[0].latitude;
            }
        });


alert(xyz);

You'll have to declare the xyz variable before the ajax call, though.

moribvndvs
  • 42,191
  • 11
  • 135
  • 149
  • Well, in all honesty my initial answer was poor. I should really stop trying to answer questions from my phone. – moribvndvs Jun 10 '12 at 22:54
  • In Chrome and firefox i'm still getting a null. In safari works well – Diolor Jun 10 '12 at 22:59
  • Hmm. I've tested with Safari, Chrome, and Firefox (on OSX). Here's a pure example http://jsfiddle.net/HackedByChinese/F2Ey5/1/ – moribvndvs Jun 10 '12 at 23:09
  • OSX here as well. In concept it seems correct (with async: false ) but I don't know... Maybe there's smthng with json. I'm not much of an expert. Thanks though! – Diolor Jun 10 '12 at 23:25
7

The real answer is NO, but you can use this:

function useXYZ(){
    alert(xyz);
}

xyz = null        

$.get('http://www.someurl.com/123=json', function(data) {
   xyz = data.positions[0].latitude;
   useXYZ();
});
gdoron
  • 147,333
  • 58
  • 291
  • 367
  • Why waste time and mental confusion on a global property? (Or closured variable). It is often better written as `function useXYZ(xyz) {..}`... and then pass through the data from the callback. –  Jun 10 '12 at 22:47
  • @pst. I thought to do so, but I wanted to show him how he can use the outer variable. (BTW, it doesn't have to be a global variable). You can edit as you wish sir! – gdoron Jun 10 '12 at 22:49
  • Thanks! Thought it work well with alert I'm still having trouble with the rest of the script. And actually when I have to put a lot of stuff inside the function useXYZ(){ ... } – Diolor Jun 10 '12 at 23:17
4

This is a common issue with Javascript. Javascript code must be written in continuation passing style. Its annoying but its something you can convert without thinking too much.

Basicaly, whenever we would have something like

var x = someSyncFunction(a, b, c);
//do something with x
console.log(x);

We can convert it into async code by making all the code after the function returns into a continuation function and turning x from a variable into a parameter of the continuation callback.

someAsyncFunction(a, b, c, function(x){
    //do something with x;
    console.log(x);
});

You have to watch out that its very easy to write confusing code. A good trick to keep in mind is taht you can make your own functions also receive callbacks. This allows them to be used by different function (just like normal sync helper functions that return a value can be used by different functions)

var getXyz = function(onResult){ //async functions that return do so via callbacks
                                 //you can also another callback for errors (kind of analogous to throw)
    $.get('http://www.someurl.com/123=json', function(data) {
       var xyz = data.positions[0].latitude;
        onResult(xyz); //instead of writing "return xyz", we pass x to the callback explicitely.
    });
};

getXyz(function(xyz){ //this would look like "var xyz = getXyz();" if it were sync code instead.
    console.log('got xyz');
});

The trick here is to change all return statements from the function into calls to the callback function. Think as if async function never returned and the only way to give a value back to someone is to pass that value to a callback.


You might ask why there isnt an easier way to do all of this. Well, there is not, unless you use another language instead of Javascript (or at least something that lets you write async code in synchronous style but automatically compiles down to regular Javascript)

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • Thanks! What if I had to grab two vars from the JSON like "xyz" for the latitude and "abc" for the longtitude? How would the onResult be and function(xyz). Could I nest them both inside it or should I create a second function(abc) ? – Diolor Jun 10 '12 at 23:46
  • You could package both values inside a single object and pass the object to the callback `onResult({lat:xyz, long:abc});`, similarly to how you would return multiple values from a synchronous function) or you could have the callback function receive two parameters instead of one `onResult(xyz, abc);`. Having more then one callback is usualy for different and mutually exclusive computation paths. A common example is having one success (or "return") callback and one error (or "throw") callback. – hugomg Jun 11 '12 at 13:19