0

my previous post was closed because it was marked as a duplicate when it wasn't and doesn't answer the question. It was suggested to ask again. The question is how do i return the object value from the jQuery $.post() function call when it's inside another function. the post they reference does not answer this question. The .then() is treated as a promise with jQuery but can't figure out how to get that value to return from the containing function.

ref post: How do I return the response from an asynchronous call?

all of the answers listed wait as expected until the ajax is complete and use a form of callback function like the jQuery .then() but none explain how to return that through a containing function, unless i'm missing it. If i'm missing it I apologize and would appreciate someone pointing out where i'm missing it.

Meisam Mahdian in the OP gave an example of using var dfd = $.Deferred(); and then returning dfd but this does not seem to work, all i get back is the $.post() prototype as does the function i'm currently using.

In other languages I would just pass the variable by reference but that doesn't exist in javascript (that i can see)

The question is how to return a promised value from a jQuery $.post() when it's inside another function. So that var thisData = getItemData(id, div); located in another script will set the variable thisData to the JSON response received from jQuery without resorting to a global variable (IE: sData in the OP).

another example is trying to get the same effect as the following but using the jQuery $.post() function in replace of the innerFunction()

var test = outerFunction();

function outerFunction() {
    function innerFunction() { return 'yay'; }
    return innerFunction();
}

I have also tried different variations of return, including a local variable and .then() modifying it and returning that. Those didn't work either.


OP:

I'd like to set a variable from a function's return data, however, there is a $.post() call inside. How do i modify the following code to return the data. i've looked at a bunch of suggestions but none seem to work.

Currently the sData inside the .then() is a global variable, i'd like to use that as the return value so a local call anywhere of var thisData = getItemData(id, div); will be the same as the current global variable sData. I saw using a callback function but this doesn't solve the issue as i'd have to use the global variable inside that callback.

forgive the complex ternary, there are 3 possible JSON types that could be returned server side.

var sData;

function getItemData(id, div) {
    typeof id !== 'undefined' ? id : '220';
    typeof div !== 'undefined' ? div : '';
    beginLoading(div);
    return $.post({
        url: '/content/itemsjson/?categoryid=' + id,
        data: { },
    })
    .done(function(data, status, request) {
        //***
    })
    .fail(function(xhr, textStatus, errorThrown) {
        //***
    })
    .always(function(data) {
        //***
    })
    .then(function(data) {
        stopLoading(div);
        sData = (typeof data == 'string') ? JSON.parse(data.responseText) : (data[0] ? data[0] : data);
    });
}
Viking NM
  • 392
  • 3
  • 17
  • The same duplicate still applies, it's just one level deeper than you're thinking. This line of code: `var thisData = getItemData(id, div);` itself returns a Promise, which is an asynchronous operation. You can `await` it or attach a `.then()` to it and use the result therein, or pass a callback to invoke within. It sounds like fundamentally you're still trying to force the process to be synchronous, which it isn't. `$.post()` returns a Promise, so if your function returns `$.post()` then your function returns a Promise. Your function is an asynchronous function like any other. – David Nov 14 '19 at 16:02

3 Answers3

2

"The question is how do i return the object value from the jQuery $.post() function call when it's inside another function"

...short answer: you can't. The "How do I return the response from an asynchronous call?" post does attempt to explain this.

You can either

a) add a "then" callback within your function which is executed when the $.post request finishes. This is the version you've got now.

or

b) make your function return the Promise/Deferred object generated by $.post, and then the calling code can attach "then" callbacks to that object, which can be executed when the $.post request finishes (and the Promise therefore resolves (or rejects)). This also means you can use a more locally-scoped variable for the response.

Something like this:

function getItemData(id, div) {
    typeof id !== 'undefined' ? id : '220';
    typeof div !== 'undefined' ? div : '';
    beginLoading(div);
    return $.post({
        url: '/content/itemsjson/?categoryid=' + id,
        data: { },
    })
}

var promise = getItemData(1, someDiv);
var sData = null;
promise.then(function(data) {
    stopLoading(someDiv);
    sData = (typeof data == 'string') ? JSON.parse(data.responseText) : (data[0] ? data[0] : data);
});

What you can never do is make your function return the data which comes back in the response to the $.post request.

Why not?

Because quite simply, it doesn't exist yet. This is because AJAX requests run asynchronously, outside the normal flow of the code.

In your original example code in the question, the order of execution goes like this:

1) Some code calls the getItemData() function.

2) getItemData starts to execute.

3) the $.post function is executed, and an AJAX request is initialised and sent

4) you run the "then" function on the Promise object returned by $.post. In this you pass a function definition, showing the Promise what to do when the request completes. This function is just a definition. It does not get executed (yet).

5) the getItemData function has no more commands in it, so it returns.

6) Some time later, the AJAX request completes. At that moment, jQuery executes the function you provided to it in the "then" method, and it receives the data returned from the server.

Hopefully you can see here how it's impossible for the value sent from the server to be returned from the getItemData function, because when that function returns, the data has not yet arrived from the server.


N.B. If you switched from using jQuery's AJAX functions to using fetch(), you could write some more natural-feeling code using async/await, as long as your calling code is within an asynchronous function itself.

ADyson
  • 57,178
  • 14
  • 51
  • 63
  • 1
    I was waiting for a cogent answer exactly like this one before closing as a duplicate, so the OP can get the best of both :) Thanks! – David Nov 14 '19 at 16:10
  • thank you. this is what the $.post().then() I was lead to believe did, why i was getting frustrated. so pull the then() out into the calling variable. is there a .fail() or something for this too so i can process errors? – Viking NM Nov 14 '19 at 17:19
  • @VikingNM yes there is. In the Promise API it's called "catch()". See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Promise_prototype . Here's the jQuery docs for it: https://api.jquery.com/deferred.catch/ – ADyson Nov 14 '19 at 17:21
  • thank you again :) – Viking NM Nov 14 '19 at 17:23
0

In fact, I think you're missing something, the result you're trying to achieve cannot be done the way you described, it's a synchronization problem. a function cannot wait for a response from $.post then return it, that's not how javascript works, you need to use a callback function instead.

mondersky
  • 441
  • 2
  • 15
-1

What you want to needs the latest JavaScript features. Please try to understand the 'async' way. The outer function needs to wait for the inner function's result. Without synchronization, run line by line but remote calls need time to wait, no way to do that.

Garry Xiao
  • 232
  • 3
  • 9