# Promise-driven animation

Inspired by this question on Stack Overflow, I've attempted to code such animation, mostly to get some more practice with async, promises and Q.js:

(Live demo)

function addOutput(s) {
$('<div>').text(s).appendTo(wnd); //return Q.defer().promise; return Q.delay(100).then(function() { return addPrompt(); }); } function addInput(s) { var l =$('.prompt:last');
}

var prompt = "kos@codepen % ";
var l = $('<div>').text(prompt).addClass('prompt').appendTo(wnd); return Q.delay(900); } function addLettersRecursive(container, s) { container.append(s.charAt(0)); // dangerous :( var row_complete = Q.defer(); Q.delay(100).then(function() { if (s.length <= 1) { Q.delay(300).then(function() { row_complete.resolve(); }); } addLettersRecursive(container, s.substr(1)).then(function() { row_complete.resolve(); }) }); return row_complete.promise; } // Usage addPrompt(">>> ") .then(function() { return addInput("whoami"); }) .then(function() { return addOutput("kos"); }) .then(function() { return addInput("uname -a"); }) .then(function() { return addOutput("Javascript in codepen.io, powered by Q.js"); }) .then(function() { return addInput("raz dwa"); }) .then(function() { return addOutput("zsh: command not found: raz"); }) .then(function() { return addInput("trzy cztery"); }) .then(function() { return addOutput("zsh: command not found: trzy"); }) .done();  I'm not really satisfied by this implementation, though. How can I simplify it? Here are the specific concerns I have: 1. I implemented addInput in terms of a recursive helper function addLettersRecursive which still is overly complicated according to my gut feeling. 2. There's this .then(function() { return function_that_returns_promise(args); }); pattern all over, which seems like a very verbose way of chaining behaviour. What I have tried: 1. I attempted to unwind the recursion by stacking the promises one on top of another in a loop, which was a bit tricky to implement because of the selective closure involved. There's some improvement but still looks messy: function addInput(s) { var container =$('.prompt:last');
var d = Q.delay(0);
for (var i=0; i<s.length; ++i) {
d = d.then(function(i) { return function() { // pass i by value
container.append(s.charAt(i));
return Q.delay(100);
}}(i));
}
return d.then(function() { return Q.delay(300); });
}

2. I'm not sure if this kind of pattern is typical to promise-driven code, or I'm just doing something sub-optimally. One thing that came to my mind is this substitution:

  /* before */ .then(function() { return addInput("whoami"); })

/* before */ return d.then(function() { return Q.delay(300); });
/* after  */ return d.then(Q.delay.bind(Q, 300));


Is it a good track?

Generally I haven't seen much "real life" uses of promises yet except the book cases, so if anything else looks out of the ordinary or sub-optimal, please raise it.

This stuff is hard to get right, at this point good promise driven code seems more like an art than engineering.

From a CodeReview perspective, your code is fairly easy to follow, except for one thing which got me stumped for a little while, row_complete should really be named char_complete, and then suddenly addLettersRecursive will make more sense.

There are at least 3 additional ways you can deal with .then(function() { return function_that_returns_promise(args); });

1. Change your functions ( like addInput ) to return a function, like this:

function addInput(s) {
var l = \$('.prompt:last');
}
}


Then you can call simply .then( addInput( 'whoami' ) )

2. Create a generic wrapper function like this:

function wrap( f ){
var args = Array.prototype.slice.call(arguments,1);
return function wrapper(){
return f.apply( this, args );
}
}


Then you can call .then( wrap( addInput, 'whoami' ) )

3. Generate a lambdafy function like this :

function lambdafy( f )
{
var lambda = function(){
var args = Array.prototype.slice.call(arguments);
return function(){
f.apply( this , args );
}
}
return lambda;
}


Then you can addInput = lambdafy( addInput ) and .then( addInput( 'whoami' ) )

• Thanks! 1 crossed my mind but probably isn't conventional, for instance Q.delay() returns the promise immediately. 2 looks very similar to Function.bind in usage, and I think I'll stick with this approach for now.
– Kos
Apr 25 '14 at 7:38