1

I am pulling json from a different application and it only gets passed when the user does something in that application.

Once I have pulled it in I am then checking to see if it equals 1 and then have a lot of other functions depending on true or false that need to be performed and only after this function has run.

I can stick all my functions in the if statements but is there a better way using callbacks?

function retrieveData (retrieveDataJson){           
    data = JSON.parse(retrieveDataJson);
    user = data.id; 
    if (user === 1) {
    //do some stuff 
    }
    else {
        // do some other stuff

    }

}
6
  • Callback? Callback means you pass some function when you call another function and using this callback in this function. Example. You can use simple functions. Do you have any problems with simple functions? Commented May 22, 2014 at 16:04
  • What I am trying to do is run the other functions once this one has executed Commented May 22, 2014 at 16:07
  • This (retrieveData) one or parse one? Commented May 22, 2014 at 16:07
  • 1
    You want promises. The idea is you call functions sequentially upon success/fail conditions. Ben Lesh has a good vanilla js implementation. jQuery has an implementation. Kris Kowal's q is the foundation for AngularJs' promise implementation. There are tons of them out there. Commented May 22, 2014 at 16:16
  • 1
    Go with Kris Kowal's q. ;) Most importantly, look for an "A+ compliant" promise library. Commented May 22, 2014 at 16:34

1 Answer 1

2

"Better" is hard to define when it comes to programming style so its hard to give a "best" answer to your question without knowing more about what you are doing and how your code is structured.

That said, one good rule of thumb is trying to keep your code organizing in terms of how you would describe your problem as opposed to writing code that only cares about control flow. Its not a hard rule though, on one end you want to avoid huge functions that do everything but on the other hand you want to avoid functions that are to small and jump around too much calling other functions or callbacks.

First of all, lets pretend that your code is only synchronous. Most languages are like this and its a shame that Javascript forces callbacks down on you. One thing you can do is create functions that receive parameters and return appropriate values. For example:

//This puts the "is user admin" logic in a single place
//Also note how we can give a good name for the function. If you have a 
//hard time naming the function its a hint that maybe you shouldn't be creating
//the function in the first place.
function isAdmin(userData){
    return userData.id === 1;
}

If its just a few lines of code that are used once, you can just leave them inline

// Names like "process X" or "do X" are not very descriptive.
//See what I mean by it would be good to know extra context?
function processUser(userData){
   // Your AJAX code should handle the JSON.Parse.
   // I prefer having the code that does the work receive the JS objects
   // because that makes things easier to test and to integrate with other JS code
   // (no need to convert things to string just to pass to this function)

   if(isAdmin(userData)){
       //do
       //some stuff
       return someValue;
   }else{
       //do some other stuff
       return someOtherValue;
   }
}

Note that I added explicit "returns" here. Even if your code isn't actually returning anything, this will come handy for understanding the transition to callbacks.

If your code gets too big you can move it to some other function:

function processAdmin(user){
    // dozens of lines of code...
    return someValue;    
}

function processUnpriviledgedUser(user){
    //...
    return someOtherValue;
}

function processUser(userData){
   if(isAdmin(userData)){
       return processAdminUser(userData);
   }else{
       return processUnpriviledgedUser(userData);
   }
}

function fetchUser(){
    //lets pretend that AJAX is synchronous for a moment...
    var rawData = $.magicAjax("www.example.com");
    var user = JSON.Parse(data);
    var val = proccessUser(user);
    return val;
}

Note that one thing we get for free with function is that we can call them from multiple places:

var result = proccessUnpriviledgedUser({id:2, name:"hugomg"});
console.log( result );

Now, lets get to callbacks. If all your "processUser" stuff is synchronous, you can probably refactor it using normal functions like I explained before. Unfortunately, if you want to do any AJAX call or otehr async stuff inside, you can't rely on return statements like before. Instead, you need to replace them with an onDone callback that receives as a parameter the stuff you would have returned.

For example, our processUser might look like

function processUser(userData, onDone){
    if(isAdmin(userData)){ // <-- we can still use sync code when not doing IO
        $.ajax("bla", {success: function(){
            //blaz;
            onDone(someValue);
        });
    }else{
        //
    }
}

function fetchUser(onDone){
    $.ajax("www.example.com", {
        success: function(data){
            var user = JSON.Parse(data);
            proccessUser(function(val){
                onDone(val);
            });
        }
    });
}

function main(){
    fetchUser(function(val){
        console.log("Fetched the user", val);
    });
}

Note how we can use the same rules we used to for splitting code in separate functions - the same idea about code size and names still applies. The only difference is that functions doing async stuff need to use callbacks instead of return. In particular, note how we added onDone callbacks to fetchUser and proccessUser. Not only did we create our own async functions, but the callback parameters mean that we don't need to hardcode what gets called after the function ends - just like return goes back to whatever caller function that called us, onDone callbacks means we jump to whatever callback the caller wants us to (instead of always jumping to the same place once we are done).

proccessUnpriviledgedUser({id:2, name:"hugomg"}, function(result){
    console.log(result);
});

Finally, I would like to point out that a big disadvantage of async code is the error handling. In order to handle "try-catch" across async functions similarly to how its handled across sync functions you might also need to pass around onError callbacks in addition to the onDone callbacks. Because this is very boilerplaty and very easy to get right, I would recommend using some sort of library to help manage your async code (either a promise based or cb based one should be OK) if you ever start writing non trivial async code.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.