Taco
Taco

Reputation: 2923

Pass data back to anonymous function via callback?

I've been researching callback functions in the JavaScript language lately and during my testing I've encountered an issue that I didn't foresee, but once I encountered it, I understood what the issue was most likely to be.

I've written two methods that work together to call the Stack Exchange API for learning purposes. The first builds the request URL and the second calls the web service itself.

function getSEWebServiceResponse(request, callback) {
    var apiRoot = 'https://api.stackexchange.com/2.2/';
    var key = 'key=s29XM)Eqn2x3YxhjLgFwBQ((';
    if (request.indexOf('?') >= 0)
        key = '&' + key;
    else
        key = '?' + key;

    getWebServiceResponse(apiRoot + request + key, callback);
}
function getWebServiceResponse(requestUrl, callback) {
    var request = new XMLHttpRequest();
    request.open('GET', requestUrl, true);
    request.onload = function() {
        if (request.status < 200 || request.status >= 400)
            callback("An unexpected error occurred.");
        else
            callback(JSON.parse(this.response));
    };
    request.send();
}

Now, this implementation is straightforward, but the issue I ran into was that passing back the response resulted in undefined and I believe the cause is that I'm using an anonymous function as the callback for getSEWebServiceResponse:

function getAssociatedAccounts(accountID, callback) {
    var url = 'users/' + accountID + '/associated';
    getSEWebServiceResponse(url, function() {
        if (!this.items) // this.items is undefined.
            return;

        var accounts = sortAccountsByReputation(this.items);
        //... DO MORE STUFF
        callback();
    });
}

I believe the simple solution is to create a defined function instead (but I feel that there should be a way to do it with anonymous functions):

function getAssociatedAccounts(accountID, callback) {
    var url = 'users/' + accountID + '/associated';
    getSEWebServiceResponse(url, processAssociatedAccounts);
}
function processAssociatedAccounts(response) {
    if (response.items)
        return;

    var accounts = sortAccountsByReputation(this.items);
    //... DO MORE STUFF
    callback();
}

A few related posts that didn't offer solutions:


Is there a way to pass variables to an anonymous callback function instead of creating a named function?

Upvotes: 0

Views: 116

Answers (2)

Quentin
Quentin

Reputation: 943157

It doesn't matter if a function is named or anonymous. All that matters is that:

  • You pass arguments when you call it
  • It does something with those arguments

For example:

let counter = 1;

function i_take_a_callback(callback) {
  callback(counter++);
}

function i_have_a_name(value) {
  console.log(`I have a name and am logging ${value}`);
}

i_take_a_callback(i_have_a_name);

i_take_a_callback(function(value) {
  console.log(`I am anonymous and am logging ${value}`);
});

Upvotes: 1

Ayush Gupta
Ayush Gupta

Reputation: 9285

In your original getAssociatedAccounts with an anonymous callback, you do not accept the response a parameter. Changing it to the following should work

function getAssociatedAccounts(accountID, callback) {
    var url = 'users/' + accountID + '/associated';
    getSEWebServiceResponse(url, function(response) { // accepted response as parameter
        if (!response.items) // this.items is now response.items.
            return;

        var accounts = sortAccountsByReputation(response.items);
        //... DO MORE STUFF
        callback();
    });
}

Upvotes: 1

Related Questions