Introduction to Promises

What is "callback hell"

Javascript that uses callbacks, is hard to get right intuitively. A lot of code ends up looking like this:

callback hell

fs.readdir(source, function(err, files) {
  if (err) {
    console.log('Error finding files: ' + err)
  } else {
    files.forEach(function(filename, fileIndex) {
      console.log(filename)
      gm(source + filename).size(function(err, values) {
        if (err) {
          console.log('Error identifying file size: ' + err)
        } else {
          console.log(filename + ' : ' + values)
          aspect = (values.width / values.height)
          widths.forEach(function(width, widthIndex) {
            height = Math.round(width / aspect)
            console.log('resizing ' + filename + 'to ' + height + 'x' + height)
            this.resize(width, height).write(
                destination + 'w' + width + '_' + filename, function(err) {
                  if (err) console.log('Error writing file: ' + err)
                }
            )
          }.bind(this))
        }
      })
    })
  }
})

So, how do we solve callback hell?

Promises!

Promise is used for deferred and asynchronous computations. A Promise represents an operation that hasn't completed yet, but is expected in the future.

Promise is in one of these states:

  • Pending
    • Initial state, not fulfilled or rejected.
  • Fulfilled
    • ​Meaning that the operation completed successfully.
  • Rejected
    • ​Meaning that the operation failed.
// You should use promises to turn this:

fs.readFile("file.json", function (err, val) {
    if (err) {
        console.error("unable to read file");
    }
    else {
        try {
            val = JSON.parse(val);
            console.log(val.success);
        }
        catch (e) {
            console.error("invalid json in file");
        }
    }
});
// Into this:

fs.readFileAsync("file.json").then(JSON.parse).then(function (val) {
    console.log(val.success);
})
.catch(SyntaxError, function (e) {
    console.error("invalid json in file");
})
.catch(function (e) {
    console.error("unable to read file");
});

As the Promise.prototype.then() and 
Promise.prototype.catch() methods return
promises, they can be chained

Creating a Promise

// We use new Promise to construct the promise. 
// We give the constructor a factory function 
// which does the actual work.

function readFile(filename, enc){
  return new Promise(function (resolve, reject){
    fs.readFile(filename, enc, function (err, data){
      if (err) reject(err);
      else resolve(data);
    });
  });
}

The passed in function will receive functions resolve and reject as its arguments which can be called to seal the fate of the created promise.

Resources

Made with Slides.com