Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery deferred : use to delay return of function until async call within function complete + get return value

How can I correctly use jQuery deferreds to delay return of function until async call within function complete + get return value?

This is my current code:

function getFields(page)
{
  var dff = $.Deferred();
  result = {};
  $.ajax( //the async call
    {
      url: page,
      success:
        function (data)
        {
          //work out values for field1 & field 2 from data here
          result = 
          {
            'field1' : field1,
            'field2' : field2
          };
        },
      complete:
        function()
        {
          dff.resolve(result); //my attempt to return the result
        }
    }
  );
  return dff.promise();
}

I want this to print {"field1":"value1","field2":"value2"}

var result = getFields('http://something');
console.log(JSON.stringify(result)); 

However, the value of result appears to be a jQuery object - so I'm doing something wrong, but what?

Thanks!


P.S. Sorry for the newbie question, I am a first time user of deferreds, so I am still grasping the basic concepts.

like image 681
bguiz Avatar asked Jul 12 '12 03:07

bguiz


People also ask

What is the use of Deferred in JQuery?

Deferred() method in JQuery is a function which returns the utility object with methods which can register multiple callbacks to queues. It calls the callback queues, and relay the success or failure state of any synchronous or asynchronous function.

How do I wait for async to complete?

Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.

How use JQuery Deferred and Promise?

If you are creating a Deferred, keep a reference to the Deferred so that it can be resolved or rejected at some point. Return only the Promise object via deferred. promise() so other code can register callbacks or inspect the current state. For more information, see the documentation for Deferred object.

How do you wait for function to finish?

Wait for function to finish using async/await keywords As you already know from the Promise explanation above, you need to chain the call to the function that returns a Promise using then/catch functions. The await keyword allows you to wait until the Promise object is resolved or rejected: await first(); second();


2 Answers

The only way to delay the return of your getFields function would be to set the AJAX async property to false:

   var ajaxPromise = $.ajax(
    {
      url: page,
      async: false  // make the call synchronous
    }
  );

But the jQuery documentation notes that this is deprecated from 1.8 onwards (i.e. it's use is discouraged).

Deferreds don't make AJAX synchronous, instead they make it easier to work with callbacks and asynchronous methods.

From what I can tell of what you're trying to it might work better to do something like this:

function getFields(page)
{
  var ajaxPromise = $.ajax( //the async call
    {
      url: page
    }
  );

  var dff = $.Deferred();
  ajaxPromise.then(function(data){

    // Possibly access the loaded data in this function.
    var result = {
      'field1' : field1,
      'field2' : field2
    };

    // Notify listeners that the AJAX call completed successfully.
    dff.resolve(result);

  }, function(){
    // Something went wrong - notify listeners:
    dff.reject(/* possibly pass information about the error */);
  });

  return dff.promise();
}

Then use the promise object like this:

var fieldPromise = getFields('http://something');
fieldPromise.done(function(result){
  console.log(JSON.stringify(result)); 
});

Note that getFields returns a Promise object immediately but you have to wait for the promise to be resolved before you can log out the result.

like image 81
Sly_cardinal Avatar answered Sep 20 '22 08:09

Sly_cardinal


Here's the basic idea of deferreds: you're returned an object, and you can use it to define functions that will be called when the return value comes back. So you could do something like:

function getFields(page)
{
    return $.ajax(page);
}

Then you can call it and specify a function to be called when the XHR call completes:

var jqXHR = getFields("/path/to/call");
jqXHR.done(function (data) { alert(JSON.stringify(data); });

The object is chainable, so you can just do this:

getFields("/path/to/call")
    .done(function (data) { alert(JSON.stringify(data); });

Note that the jqXHR object returned by $.ajax is a Deferred-compatible object, so you can read the documentation at http://api.jquery.com/category/deferred-object/.

I'm not sure what you meant by your sample code (since it doesn't actually use the Ajax call) but maybe you meant something like this:

function getFields()
{
    var df = $.Deferred();
    window.setTimeout(function () {
        df.resolve({field1: "value1", field2: "value2"});
    }, 1000);
    return df.promise();
}

getFields().done(function (data) { console.log(JSON.stringify(data)); });

This will print your desired value a second after you run it.

like image 40
Anthony Mills Avatar answered Sep 17 '22 08:09

Anthony Mills