ctag
ctag

Reputation: 634

JavaScript: using callbacks to control program flow

I'm still trying to get oriented with JS, and have recently had a lot of trouble understanding the role of callbacks.

I can see that callbacks offer a more asynchronous(?) way of returning values generated in a function. For example, this makes sense to me:

function summation (a, b, _callback) {
 if (typeof(_callback) === 'function') {
  _callback(a+b);
 }
}

$(document).ready(function () {
 summation(2,3,function (_val) {
  console.log(_val);
 }
});

As opposed to something like var _val = summation(2,3); Where var isn't available immediately following the assignment.

I have difficulty making this process scale as I attempt to manipulate elements on a webpage with jQuery. I have an object which tracks elements:

function createObj (_callback) {
 var test = new Object();
 test.mainPane = $('#mainPane');
 if (typeof(_callback) === 'function') {
  _callback(test);
 }
}

If I wish to pass test.mainPane into a function fitToPage() which adjusts the properties of the element to fit a given screen size, and then want to pass the element to another function createElems() which adds children to the element, things begin to fall apart:

$(document).ready(function () {
 createObj(function (test) {
  fitToPage(test, function (test) {
   createElems(test, null);
  });
 });
});

And it only seems to get worse if I try avoiding this callback hell(?) by creating special functions which do nothing but help me manage the callbacks to other functions. I'm confident that I've missed something important, but haven't come up with the correct search terms to find it. Is there a better method?

Upvotes: 0

Views: 202

Answers (2)

c-smile
c-smile

Reputation: 27470

JavaScript execution model is synchronous by design. So if you have function call in code the function body will be executed immediately, synchronously and without interruption by other tasks. Therefore this

function summation(a,b) {
  return a + b;
}
var r = summation(1,2); // -> 3

will be executed as it is written.

At the same time you can ask browser runtime environment to call [back] your function (callback per se) when some event will happen. Therefore your function will be called asynchronously:

function doSomethingWhenDocumentIsLoaded() 
{
  // document ready, do something with it.
}

$(document).ready(doSomethingWhenDocumentIsLoaded);

Here we defined function and asked the runtime to call that function back when the document will be loaded/ready for operation.

Upvotes: 0

Scott Sauyet
Scott Sauyet

Reputation: 50807

You've run across one of the main issues involved in using callbacks to work with asynchronous code. Asynchronicity is contagious. Once you start to use it in one spot, the surrounding code also needs it, and then the code around that, and so on.

One of the more popular ways to deal with this at the moment is Promises. These don't actually eliminate the callback issues, but they let you deal with them in a simpler manner syntactically. The idea is that instead of accepting a callback, a function returns an object to which the caller can attach a callback that will be processed later. In the promise libraries, these object must expose a then method that takes a success and an error callback. I don't know if jQuery's ready method exposes it, so this might not be quite right, but it should be close to how you would rework your example with Promises:

$(document).ready()
    .then(createObj)
    .then(fitToPage)
    .then(function(test) {return createElems(test, null)});

And if you have a version of createElems that partially applied the null, then that last line could simply be

    .then(createElems2);

Upvotes: 1

Related Questions