0

I would like to show off how much cleaner jQuery deferred objects can make the code instead of using the "callback hell".

I have no option to switch to Javascript's Promises.

Here is the "bad" code:

/* Callback Hell !? */

// Main

var stringToProcess = "1,2,3,4,5,6";

console.debug("Main Stack: start");

convertStringToArray(stringToProcess, function (convertedString){
    convertToObject(convertedString, function(objectOfStrings){
        resetObjectValues(objectOfStrings, function(object){
            console.debug(object);
        });
    });   
});

console.debug("Main Stack: end");



// Functions

function resetObjectValues(object, callback){
    for(var key in object){
        object[key] = "X";
    }

    setTimeout(function thirdcb(){
        callback(object);
    }, 500);
}

function convertToObject(string, callback){
    var object = {};
    string.map(function(current, index){
        object[index] = current;
    });

    setTimeout(function secondcb(){
        callback(object);
    }, 500);
}

function convertStringToArray(string, callback){
    var delimiter = ",";
    var arrayString = string.split(delimiter);

   setTimeout(function firstcb(){
        callback(arrayString);
    }, 500);

}

And thats how I tried to make it better:

/* Promise Heaven... */


// Main

var stringToProcess = "1,2,3,4,5,6";

console.debug("Main Stack: start");

var promise;
promise = convertStringToArray(stringToProcess);
promise.done(function(string){
   promise = convertToObject(string);
   promise.done(function(object){
       promise = resetObjectValues(object);
       promise.done(function(object){
           console.debug(object);
       })
   })
});

console.debug("Main Stack: end");

// Functions

function resetObjectValues(object, callback){
    var deferred = $.Deferred();
    for(var key in object){
        object[key] = "X";
    }

    setTimeout(function thirdcb(){
        deferred.resolve(object);
    }, 500);

    return deferred.promise();
}

function convertToObject(string){
    var deferred = $.Deferred();
    var object = {};
    string.map(function(current, index){
        object[index] = current;
    });

    setTimeout(function secondcb(){
        deferred.resolve(object);
    }, 500);

    return deferred.promise();
}

function convertStringToArray(string){
    var deferred = $.Deferred();
    var delimiter = ",";
    var arrayString = string.split(delimiter);

   setTimeout(function firstcb(){
       deferred.resolve(arrayString);
    }, 500);

    return deferred.promise();

}

...sadly the .done() code looks almost as bad as the "hell" one. I cannot figure our how to chain the returns of promises/deferred properly. I saw tutorials where they do it without arguments to the function calls. But I have arguments to throw in - so how to get along with that?

xetra11
  • 7,671
  • 14
  • 84
  • 159
  • Is your code just for demo purposes, as it doesn't need to be async at all. – Rory McCrossan Jun 09 '16 at 13:47
  • You're supposed to use [`then`](http://api.jquery.com/deferred.then/) instead of `done`, so that you can [flatten the chain](http://stackoverflow.com/a/22000931/1048572): `convertStringToArray(stringToProcess).then(convertToObject).then(resetObjectValues).then(console.debug.bind(console));` – Bergi Jun 09 '16 at 13:59

1 Answers1

2

The chaining of promises should look somewhat like this:

convertStringToArray(stringToProcess)
  .then(function(string){
    return convertToObject(string);
  })
  .then(function(object){
    return resetObjectValues(object);
  })
  .then(function(object){
    console.debug(object);
  });

Basically each (callback) function returns a new promise, which can then be used to attach others handlers to it. That way you don't need the nesting of callbacks like in your code.

Sirko
  • 72,589
  • 19
  • 149
  • 183
  • 1
    Except that using `done` doesn't work. Only the `then` method returns new promises and chains. – Bergi Jun 09 '16 at 13:56