0

I'm using pretty standard setup I think. A click on element to call a function that handles an ajax request.

My limited understanding of variable scope and callbacks when using asynchronous anything and trying to figure out jQuery deferreds is making my feeble brain hurt.

$('<div>')
.on({
    click : function(){
        console.log(
            fetchMyData() // this will be 'undefined' but why?
        )
    }
})

function fetchMyData(){
    $.ajax({
        // ajax setup
    })
    .done(function(response){
        console.log( response ); // shows 'hello' as expected
        return response; 
    })
}

I get that the ajax call will not necessarily be done by the time I'm doing the console.log(), since it's asynchronous of course.

So how can I make it such that fetchMyData() will display the ajax result once it's ready?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
tim
  • 3,823
  • 5
  • 34
  • 39
  • What are you trying to do? `fetchMyData()` logs as `undefined` because it doesn't return anything. Is there a reason you are avoiding `.done()`? – Smern Jul 16 '13 at 20:06
  • Returning anything inside of a `done` callback does effectively nothing. You could use `return $.ajax({...` in your `fetchMyData` function. Then in your click handler, use `fetchMyData.done(function() { console.log("foo"); });` – Ian Jul 16 '13 at 20:10
  • put the code that displays the result where your return statement currently lives... – dandavis Jul 16 '13 at 20:13

3 Answers3

2

You should change what fetchMyData function does. Try returning the promise object.

$('<div>').click(function()
{

    var fetchMyDataPromise  = fetchMyData() ;

    fetchMyDataPromise.done(function(response)
    {
        console.log(response);
    });

});

function fetchMyData()
{
    return  $.ajax({ // ajax setup });
}  
Tomas Santos
  • 560
  • 4
  • 12
1

So how can I make it such that fetchMyData() will display the ajax result once it's ready?

You've already done that, in the .done callback. If you want fetchMyData to return the response, you have to use a synchronous call, which is usually not the right thing to do (because the UI will freeze until the response arrives).


Maybe you want to modify your function to take a callback:

function fetchMyData(thenDoThis){
    $.ajax({
        // ajax setup
    }).done(thenDoThis)
}

function doSomethingWithResponse(response) {
    // do something
}

Then call it like this:

fetchMyData(doSomethingWithResponse);

Or like this:

$('<div>').click(function() {
    fetchMyData(function(response){
        console.log(response);
    });
});
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • thanks. That is what I thought. Any way to avoid callbacks? Because to me it feels like overly complex code. @L105 is talking about `.when()` which sounds intriguing – tim Jul 16 '13 at 21:56
  • 2
    The other suggestions (by L105 and Tomas Santos) both imply that you pass a function to be called when the response arrives, so they're just different syntax for callbacks (relying on promises, which are indeed very interesting). That's not overly complex, it's the standard way to deal with asynchronous operations. The only way to avoid it is using synchronous request, which, as I mentioned, is not good... – bfavaretto Jul 16 '13 at 23:08
  • yeah, I've battled that fight for a long time, using `async:false` and finally accepted that it's just asking for trouble. I don't recommend using synchronous AJAX, aka `SJAX` – tim Jul 17 '13 at 00:58
1

You can use jQuery When like this :

$('<div>')
    .on({
        click : function() {

           $.when(fetchMyData()).then(function(data) {
                    console.log(data);
           });
         }
    });

    function fetchMyData(){
        return $.ajax({
            // ajax setup
        });
    }
L105
  • 5,379
  • 3
  • 18
  • 23
  • that's interesting. But now I have to do the setup in the click handler. There must be a way to mimic synchronous behavior so I can just write `console.log( fetchMyData() );` – tim Jul 16 '13 at 22:09