Can I make a synchronous promise in the JavaScript Q library?

PP. picture PP. · Jun 20, 2013 · Viewed 18.6k times · Source

I want to do something like the following:

delay( 2500 )
  .then( function () { console.log( "Step 1 done" ) } )
  .then( delay( 7500 ) )
  .then( function () { console.log( "Step 2 done" ) } );

So implementation of delay has been demonstrated many times before:

function delay( ms ) {
  var deferred = Q.defer();
  setTimeout( deferred.resolve, ms );
  return deferred.promise;
}

But if I run the above in node.js I get:

... delay of 2500ms
Step 1 done
Step 2 done
... delay of ~7500ms

rather than what I expect to see:

... delay of 2500ms
Step 1 done
... delay of 7500ms
Step 2 done

In the examples provided on https://github.com/kriskowal/q/wiki/Examples-Gallery I can't find any examples of synchronous functions (functions that return a value without any callbacks involved) chained with promise functions.

Any ideas how to mix in synchronous actions with asynchronous promises?

I've tried:

function synchronousPromise() {
  var deferred = Q.defer();
  console.log( "Synchronous function call" );
  deferred.resolve();
  return deferred.promise;
}

delay( 2500 )
  .then( function(){synchronousPromise()} )
  .then( function(){delay( 7500 )} )
  .then( function(){synchronousPromise()} );

And this outputs:

... delay of 2500ms
Time now is 2013-06-20
Time now is 2013-06-20
... delay of 7500ms

.. still not what I'm trying to achieve.

Answer

Felix Kling picture Felix Kling · Jun 20, 2013

If you want to chain the callbacks, you have to return a new promise object from one of the callbacks. In your first example, you write

.then( delay( 7500 ) )

which means you are passing a promise object to .then, not a function. According to the Promise/A+ proposal (which Q follows), all non-function arguments must be ignored. So, basically it's the same as if you just write:

delay( 2500 )
  .then( function () { console.log( "Step 1 done" ) } )
  .then( function () { console.log( "Step 2 done" ) } );

Instead, pass function which calls delay and returns the promise object:

delay( 2500 )
  .then( function () { console.log( "Step 1 done" ); } ) 
  .then( function () { return delay( 7500 ); } )
  .then( function () { console.log( "Step 2 done" ); } );

Now the last callback will only be called once the promise object returned by delay in the second callback is resolved.