JavaScript Basics:
Promises

Casey A. Ydenberg

@CAYdenberg

CAYdenberg

ydenberg@gmail.com

caseyy.org

Eleven: Promise?

Mike: It's something you can't break. Ever.

We are committed to ensuring that 2015 will be the last federal election conducted under the first-past-the-post voting system.

What is a Promise?

A promise is a container for an asynchronously delivered value
-- Dr. Alex Rauschmayer

Recap: Synchronous vs asynchonous code

In PHP:


$data = file_get_contents('http://a/resource/somewhere');
                  

In JavaScript:


  http.get('http://a/resource/somewhere', function(res) {
    // deal with response
  });
                    

Callbacks vs Promises

Callback


http.get('http://a/resource/somewhere', function(res) {
  // deal with response
});
                      

Promise


httpPromise.get('http://a/resource/somewhere').then(function(res) {
  // deal with response
});
                      

Advantages

  • Readability
  • Dealing with errors
  • Chaining and returning

Types of Promises

  • jQuery deferred (https://api.jquery.com/category/deferred-object/)
  • Q (https://github.com/kriskowal/q)
  • Bluebird (https://github.com/petkaantonov/bluebird)
  • ES6/A+ specification

Can I use it?

Since Node.js 0.12

Polyfill: https://github.com/stefanpenner/es6-promise

... Babel

Creating Promises


function wait(time) {
  return new Promise(function(resolve) {

    setTimeout(function() {
      resolve('You kept your Promise!');
    }, time);

  });
}

wait(1000).then(function(msg) {
   console.log(msg)
});
                  

function fetchUrl(url) {
  return new Promise(function(resolve, reject) {
    http.get(url, function(response) {
      if (response.status === 200) {
        return resolve(response.body);
      else {
        return reject(Error('Not Found'));
      }
    });
  });
}
                  

Using Promises


const url = 'https://api.forecast.io/forecast/APIKEY/50.1149639,-122.9486474';
fetchUrl(url).then(function(data) {
  console.log(data);
}, function(err) {
  console.log(err);
});
                  

... or ...


fetchUrl(url).then(function(data) {
  console.log(data);
}).catch(function(err) {
  console.log(err);
});
                  

The real power: multiple async operations

Imagine you're getting some data from a database, and then processing it asynchonously:


getDataFromDb(params, function(data) {
  processData(data, function(processedData) {
    // deal with data
  });
});
                  

If we encapsulate this logic in a function, what do we return?

Wrap everything in a single promise


function queryDb(params) {
  return new Promise(resolve, reject) {

    getDataFromDb(params, function(data) {
      processData(data, function(processedData) {
        resolve(processedData);
      });
    });

  });
}

queryDb.then(...);
                

Chaining promises

.then always returns another promise. Very useful.


myPromise.then(function(dataOne) {
  // process dataOne and create another promise
  return myOtherPromise(dataOne);
}).then(function(dataTwo) {
  // do something with dataTwo
});
                

Chaining advantages:

  • Break the chain anywhere and return. Separate logic based on what makes sense.
  • .catch at the end will handle error anywhere in the chain.
  • You can return another promise but deal with the result of that promise.

Parallel Promises


var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    return "Resolved"
  }, 1000);
});

Promise.all([p1, p2, p3]).then(function(values) {
  console.log(values); // [3, 1337, "Resolved"]
});

                

... but don't forget to catch

What the actual flying fuck? Promises swallows errors by default! Who’s idea was that?

-- Reddit user /u/ledp

new Promise(function(resolve, reject) {
  resolve('promised value');
}).then(function(value) {
  throw Error('error');
}).catch(function(error) {
  console.error(error.stack);
});
                

http://jamesknelson.com/are-es6-promises-swallowing-your-errors/

Acknowledgements