Converting a recursive function into an asynchronous CPS implementation (javascript)

You might want to have a look at my recent answer or this older one (Demo), on how to implement such an effect.


Tip: Don’t clone the elements into new ones, just hide them and make them appear part-for-part.

Also, it might be easier not to deal with jQuery instances at all but native DOM elements. So yes, a rewrite might do 🙂 And I think it does need a stack as well.

function animate(elements, callback) {
/* get: array with hidden elements to be displayes, callback function */
    var i = 0;
    (function iterate() {
        if (i < elements.length) {
            elements[i].style.display = "block"; // show
            animateNode(elements[i], iterate); 
            i++;
        } else if (callback)
            callback();
    })();
    function animateNode(element, callback) {
        var pieces = [];
        if (element.nodeType==1) {
            while (element.hasChildNodes())
                pieces.push(element.removeChild(element.firstChild));
            setTimeout(function childStep() {
                if (pieces.length) {
                    animateNode(pieces[0], childStep); 
                    element.appendChild(pieces.shift());
                } else
                    callback();
            }, 1000/60);
        } else if (element.nodeType==3) {
            pieces = element.data.match(/.{0,2}/g); // 2: Number of chars per frame
            element.data = "";
            (function addText(){
                element.data += pieces.shift();
                setTimeout(pieces.length
                    ? addText
                    : callback,
                  1000/60);
            })();
        }
    }
}

animate($("#foo").children());

Demo at jsfiddle.net

How it works:

  • The addText function adds some character to the current text node, and sets a timeout for itself – animation! In case everything is done, it invokes the callback function.
  • childStep runs the animation on a childnode, and passes itself as the callback until no children are left – then nvokes the callback function.
  • Both together, animateNode recursively runs over the node tree and animates the textnodes in thier order.
  • the iterate function calls animateNode (after unhinding them) on all input elements, by passing itself as the callback. After all input elements are finished, it invokes the outer callback which is given as the second argument to animate.

Leave a Comment