Promises – with Q

Promises – with Q

0 0


A lab and presentation about Q promises

On Github andersjanmyr / promise-lab


with Q

Anders Janmyr @andersjanmyr



Promises, what?

A promise is an object that represents the return value or the thrown exception that the function may eventually provide.



Promises, why?

To bring composability and error handling to asynchronous programming.

Callback (successful)

function asyncHello(what, callback) {
    setTimeout(function() {
        callback(null, 'Hello ' + what);
    }, 100);
asyncHello('Tapir', function(err, hello) {
    if (err) return console.error('Failure');

Callback (failing)

function asyncFail(what, callback) {
    setTimeout(function() {
        callback('I fail, therefore I am');
    }, 100);
asyncFail('Tapir', function(err, hello) {
    if (err) return console.error('Failure');
    // do something

Callback (error)

function asyncError(what, callback) {
    try {
        return callback(null, JSON.parse(what));
    } catch (error) {
        return callback(error);


promise.then(onFulfilled, onRejected)



// Same as
promise.then(null, onRejected)


promise.then(onFulfilled, onRejected)
.finally() // Clean up resources


  • If you return a value in a handler, outputPromise will get fulfilled.
  • If you throw an exception in a handler, outputPromise will get rejected.
  • If you return a promise in a handler, outputPromise will “become” that promise. Being able to become a new promise is useful for managing delays, combining results, or recovering from errors.

Chaining and nesting

function authenticate() {
    return getUsername()
    .then(function (username) {
        return getUser(username);
    // chained because we will not need the user name in the next event
    .then(function (user) {
        return getPassword()
        // nested because we need both user and password next
        .then(function (password) {
            if (user.passwordHash !== hash(password)) {
                throw new Error("Can't authenticate");

Creating Q(value)

  • If value is a Q promise, returns the promise.
  • If value is a promise from another library it is coerced into a Q promise (where possible).
  • If value is not a promise, returns a promise that is fulfilled with value.

Creating (fcall)

// Creates a promise from a value
return Q.fcall(function () {
    return 10;

Creating (deferred)

// Interfacing with async functions
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
    if (error) {
        deferred.reject(new Error(error));
    } else {
return deferred.promise;

Creating with Node functions

return Q.nfcall(FS.readFile, "foo.txt", "utf-8");
return Q.nfapply(FS.readFile, ["foo.txt", "utf-8"]);

Creating with nbind

var Kitty = mongoose.model("Kitty");
var findKitties = Q.nbind(Kitty.find, Kitty);

findKitties({ cute: true }).done(function (theKitties) {


Combination (all)

return Q.all([
    eventualAdd(2, 2),
    eventualAdd(10, 20)
then gets an array of results.

Combination (spread)

Q.all([getFromDisk(), getFromCloud()])
.spread(function (diskVal, cloudVal) {
    assert(diskVal === cloudVal);



var funcs = [foo, bar, baz, qux];

//With a loop
var result = Q(initialVal);
funcs.forEach(function (f) {
    result = result.then(f);
return result;


var funcs = [foo, bar, baz, qux];

//With reduce
return funcs.reduce(function (soFar, f) {
    return soFar.then(f);
}, Q(initialVal));

// Or compact
return funcs.reduce(Q.when, Q());


// when is the static equivalent of then
return Q.when(valueOrPromise, function (value) {
}, function (error) {

End (Promises)

with Q

Anders Janmyr @andersjanmyr