6
\$\begingroup\$

I keep running into the same pattern with code using promises in javascript.

When writing a function which takes a promise and returns a promise, obviously I want to reject the promise I'm returning when the promise I received is rejected (and usually I want to pass the error down the chain verbatim). This results in a fair amount of boilerplate:

var fs = require ('fs');
var when = require ('when');
var nodefn = require ("when/node/function");

var get_some_data = function (filename) {
    return nodefn.call (fs.readFile, filename);
};

var parse_some_data = function (filename) {
    var deferred = when.defer ();

    var input = get_some_data (filename);
    input.then (function (data) {
        // imagine some complicated but synchronous process here which
        // may also call deferred.reject() if something goes wrong.
        deferred.resolve (JSON.parse (data));
    }, function (error) {
        deferred.reject (error);
    });

    return deferred.promise;
};

var do_something = function (filename) {
    var deferred = when.defer ();

    var input = parse_some_data (filename);
    input.then (function (data) {
        // imagine some complicated but synchronous process here which
        // may also call deferred.reject() if something goes wrong.
        data['foo'] = 'bar';
        deferred.resolve (data);
    }, function (error) {
        deferred.reject (error);
    });

    return deferred.promise;
};

Is there a better way to structure this code? Do promise libraries have features which I'm not using, which would reduce the boilerplate? (The above code uses when from cujo.js, but if other promise libraries have better solutions I'm interested in hearing about them).

\$\endgroup\$

migrated from programmers.stackexchange.com Jan 26 '14 at 16:23

This question came from our site for professionals, academics, and students working within the systems development life cycle.

3
\$\begingroup\$

You're making more work for yourself than necessary.

Check this out:

var fs = require('fs');
var nodefn = require("when/node/function");

var get_some_data = function(filename) {
  return nodefn.call(fs.readFile, filename);
};

var parse_some_data = function(filename, throwError) {
  return get_some_data(filename).then(function(data) {
      // Mimic a synchronous error
      if (throwError) {
        throw new Error('Error parsing data')
      }

      return JSON.parse(data);
    });
};

var stringify_some_data = function(filename, throwParseError, throwLogError) {
  return parse_some_data(filename, throwParseError).then(function(parsedData) {
    // Mimic a synchronous error
    if (throwLogError) {
      throw new Error('Error stringifying data.');
    }

    return JSON.stringify(parsedData);
  });
};

var onSuccess = function(dataString) {
  console.log('Success! ' + dataString);
};
var onError = function(err) {
  console.log('Error! ' + err.message);
};

// "Success! { "data": "obj" }"
stringify_some_data('./data.json').then(onSuccess, onError);

// "Error! ENOENT, open './not_a_file.json'"
stringify_some_data('./not_a_file.json').then(onSuccess, onError);

// "Error! Error parsing data"
stringify_some_data('./data.json', true).then(onSuccess, onError);

// "Error! Error stringifying data."
stringify_some_data('./data.json', false, true).then(onSuccess, onError);

A couple of things to note:

  • An error thrown anywhere in the promise chain (synchronous or not) will bubble down to your onError handler
  • Return values of Promise objects are passed as arguments to the next onSuccess handler

I'm still working on grokking how the Promise/A+ spec works. If you've used jQuery.Deferred, you should know that it does not follow the spec (which made using When.js a big learning curve for me). Here's a pretty decent article explaining the Promise/A+ spec. Brian Cavalier (a When.js author) has some blog posts on asynchronous programming which are worth reading, as well.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.