Click here to share this article on LinkedIn »

It’s been a while, but I promised I would write this post, so here it is. First things first, let’s make sure you’re even in the right place with a quick example. Here’s a promise you’ve probably used before:

Chances are you’ve used the above snippet dozens of times without really thinking about how it works. First it might help to understand what a callback is, so you might want to read my previous piece on callbacks if you’re unfamiliar with the term. Promises clean up the infamous callback hell that you’ve probably heard of before. It looks something like the reincarnation of Steve Buscemi as a code block.

fs.readdir(source, function (err, files) {

getData(function(x){

getMoreData(x, function(y){

getMoreData(y, function(z){

...

});

});

});

Pretty ugly, eh? Don’t worry you’ll never have to see that again. Promises aim to make asynchronous code look a little more like Ryan Gosling, but unfortunately they don’t get quite there. You’ll have to read my next piece on async/await for that (hold your pants I’ll be quicker with this one).

So what exactly is a promise? Well, as most code goes, the definition doesn’t do it justice, especially if you’re just learning to code and some things still look like hieroglyphics. A promise is essentially an object that represents the completion or failure of an asynchronous operation (Mozilla). In layman terms, a promise is an object returned by an asynchronous function, like an ajax call, which promises to run code whether that function succeeds or fails. The promise object usually has at least two primary methods (functions) called then and catch . Unfortunately some libraries, like jQuery, like to be special and implement them in their own way. So you may see then replaced by done or catch replaced by fail . Make sure you read the docs!

The then and catch methods each take one argument, the infamous callback function, which will be run when the function’s purpose is fulfilled or fails, respectively. Lets break this down with some code:

// The function below returns a promise object.

// You can think of the the result of this function as an object

// that looks like this { then: function..., catch: function... }

// so that's why you can chain the then/catch functions onto it asynchronousFunction() // immediately returns promise when called // when the asynchronous operation completes,

// the callback (anonymous function) you pass here is run

.then(function(result) { // the optional result is passed/injected into your callback

// now you can use it in something like...

$('.some-class').text(result.something)

})



// if the operation fails the error

// will be passed/injected into the catch callback

.catch(function(err) { // do something with the error such as

// showing it to the user in the html markup or

console.log(err);

})

Starting to look a lot like $.ajax huh? So now you’re like “well cool you just showed me what I’ve already been using, thanks a lot.” Don’t worry, I’m just laying down the ground rules before I show you how to create your own promises.

Before we do though let’s remind you a little thing about callbacks. Remember that callbacks are just functions that are passed as arguments and called by another function. Thus, the previous example could be written like this and work exactly the same:

function successCallback(result) {

$('.some-class').text(result.something)

} function errorCallback(err) {

console.log(err);

} asynchronousFunction()

.then(successCallback)

.catch(errorCallback)

Remember that anonymous functions, like in the first example, are just shorter ways of writing what I have above, and that in javascript functions can be passed as arguments like any other data type! Ok, so, if things are starting to clear up about the usage of promises, lets move on to creating them. If not, copy the jQuery code at the top and mess with it until you’re satisfied (it works).

ES2015, or ES6, comes with built in promises. So you can create asynchronous functions without importing any libraries. This is supported by all major browsers (except Internet Explorer, obviously). So we can do something like this:

// this function, waitThreeSeconds, returns a promise function waitThreeSeconds() { // below is the constructor for the promise. It takes a

// callback that accepts two arguments,

// resolve and reject (functions)

// you call these functions when the code succeeds or fails return new Promise(function(resolve, reject) { setTimeout(function() { // resolve the promise after 3 seconds

// the function you pass to 'then' will be called

resolve(); }, 3000);

})

} // call the asynchronous function, which returns our promise

waitThreeSeconds() // chain the 'then' method, which accepts a callback to

// be called when the promise is rsolved

.then(function() {

alert('It\'s been three seconds!');

}) // we don't need a catch method in this example, because the

// promise has no potential to fail (be rejected)

Try this on repl.it and see for yourself! As you can see above, you’re not required to chain a catch function, but if your code had the potential to fail, you would have to handle it in the promise with reject and then use catch when you call the function to handle the rejection.

The code above is pretty useless in real life, so let me give you an example of something you might actually use a promise for. Let’s say you want to make a function that prompts the user to upload a file, and once the file is chosen (or not) you want to show the user a message on the page. Check out this jsfiddle to see the html markup and css.

function promptUserForFile() { return new Promise(function(resolve, reject) { // call the click event on a hidden file input

$('#file-input').click();



// set an interval to check if the document regains

// focus (when the file dialog closes). If no file

// was chosen, reject the promise

const interval = setInterval(function() {

const fileCount = $('#file-input')[0].files.length;

if (document.hasFocus() && !fileCount) {

clearInterval(interval)

reject();

}

}, 1000);



// if the file input changes, resolve the promise

// and pass it the file name

$('#file-input').on('change', function() {

const filePath = $(this).val();

const fileName = filePath.split('\\').pop();

clearInterval(interval)

resolve(fileName);

})

})

} $('button').on('click', function() { // call the asynchronous function

promptUserForFile()



// when it's resolved (file chosen), set the success text

.then(function(fileName) {

$('.file-chosen-message').text('File chosen: ' + fileName);

})



// when it's rejected (no file), set the error text

.catch(function() {

$('.file-chosen-message')

.text('no file chosen')

.addClass('error');

})

})

Ok I know this is a lot. But let’s try to break it down into some easy to read steps.

Create an asynchronous function promptUserForFile , which returns a promise object. The function calls a click event on a hidden file input, that we chose to hide because they are ugly and we want our own markup. The promise sets up an event listener on the file input, to watch for changes. Which only occurs when the user selects a file. If the file input changes, we resolve the promise and pass it the file name. It also sets up an interval that will watch to see if the document regains focus, which will happen when the file upload dialog closes. If the interval detects the dialog has closed (document regains focus) but the user did not select a file, it will reject the promise. Both the resolve and reject will clear that interval so it can be set up again the next time the user clicks the button. Next, we set up the click listener on our custom button, which looks a lot better than the native file input. The click event triggers our asynchronous function, pomptUserForFile and passes two callbacks to then and catch . The then and catch callbacks will set some text on the page whether the user has chosen a file or not, aka when the promise is resolved or rejected. You could imagine that we can put whatever we want in these callbacks, so that our promise handling is very versatile. For example, we could show the image on the page if we wanted to.

Alright so we’ve come up with a practical example for when we might want to use our own promise. What a journey! I hope this article has shined some light on how to use and create promises. If anything is unclear, please say so in the comments and I’ll make necessary updates! One love, Joey.