-->

Why is my Jquery ajax success handler being called

2019-07-19 07:09发布

问题:

I have a function which makes two rest calls to the google spreadsheetAPI. I use a $.when to make sure that the data fron thefirst call is process before dealing with the data from the second call.

The problem is that the first ajax handler(getRealNames), receives a javascript object as its argument, but the second handler(displayTeams), receives an array, the 0th element is the object I was expecting to get.

Why does one get an object and the other get an array? They are calling the same rest api. The array did not appear until I refactored the code to use deferreds instead of callback nesting. So I think this is a jquery question rather than a spreadsheetAPI question.

(see screen shot below, I've console.log'ed the arguments received by both handlers

//this is the function generating the REST requests, I just put it in for completeness
function getWorkSheet(doc_key,sheet){
  return $.get('https://spreadsheets.google.com/feeds/list/'+
    doc_key+'/'+sheet+
    '/private/full?alt=json&access_token=' 
    + googleAPItoken)
    .fail(function(){
      alert("failed to get google doc:"+doc_key+" ,sheet: "+sheet);
    });

  }

 function getRWMTeams() {
    var nameQuery=getWorkSheet(doc_key,1);
    nameQuery.done(getRealNames);

    var repoQuery=getWorkSheet(doc_key,2);

    //the deferred:'namesProcessed' is resolved in getRealNames
    $.when(repoQuery,namesProcessed)
      .done(displayTeams);

  }

回答1:

Eventually, more careful reading of the api doc(http://api.jquery.com/jQuery.when/) revealed the following comment in a code sample;

// a1 and a2 are arguments resolved for the page1 and page2 ajax requests, respectively.
// Each argument is an array with the following structure: [ data, statusText, jqXHR ]

I had read the first comment, and assumed that the arguments were simply the return data. The second comment reveals the source of my problem.



回答2:

Notwithstanding this being an old, answered question, it deserves a more complete answer before jQuery moves into its Promises/A++ era (anticipated some time in 2015).

Unlike other promise libs, jQuery promises can be resolved with multiple values. This makes life somewhat awkward for jQuery.when().

The documentation says :

The arguments passed to the doneCallbacks provide the resolved values for each of the Deferreds, and matches the order the Deferreds were passed to jQuery.when().

and goes on to explain how the doneCallback arguments behave for different numbers of resolved values - and this is where it gets a bit crazy :

  • No value: The corresponding argument will be undefined.
  • A single value: The corresponding argument will hold that value.
  • Multiple values: The corresponding argument will be an array of those values.

What you are seeing is the third case - the three values returned by jQuery.ajax() - data, textStatus and jqXHR - bundled into an array. This is unavoidable when working with a jqXHR promise directly.

However, there is a workaround. If you arrange for getRealNames() to include a chained .then(), it can be made to discard textStatus and XHR, and return a promise of just data - and hence give the single value behaviour described above. For example :

function getRealNames() {
    return $.ajax(...)
        .then(function(data, textStatus, jqXHR) {
            return data;
        });
}

That's all you need to do, but your getRWMTeams() function can also be tidied, as follows :

function getRWMTeams() {
    var repoQuery = getWorkSheet(doc_key, 2);
    var namesProcessed = getWorkSheet(doc_key, 1).then(getRealNames);
    return $.when(repoQuery, namesProcessed).then(displayTeams);
}

or

function getRWMTeams() {
    return $.when(
        getWorkSheet(doc_key, 2), 
        getWorkSheet(doc_key, 1).then(getRealNames)
    ).then(displayTeams);
}


回答3:

Thanks for asking this question, and also providing the answer. I have been having the exact same problem and trying to understand the reasoning behind "the arguments being an array" has been a challenge.

Now that I understand why the argument is array, I notice that only the first argument is an array. The second argument simply contains the data (from the resolved deferred). Do you notice this too? Here is a screenshot to explain more:

'fields' and 'defn' are my arguments in the done callback. One is an array and the other is an object. I would love to know your thoughts on this.