Community Post

Writing Your Own Javascript Promises

Wesley L. Handy

Some things about coding are easy to learn. Why? Well, tons of tutorials across plentiful platforms for free or by forking over some fees, that's why. Not to mention a youtube channel or two, or three, or... Well, you get the picture.

Even with all the resources, not everything is as easy to learn, and sometimes because there are too many resources to weed through. For me, I could use functions that were promised-based and I had heard of promises and could read the MDN documentation, but it was really hard to find a clear tutorial on how to write a Promise.

So, What is a Promise?

If anyone asks you a question about Javascript, ever, your default answer should be 'an object.' And you will be right, even if you don't realize it. Promises are no different.

Promises are objects. To quote the MDN documentation directly:

The Promise object is used for asynchronous computations. A Promise represents a value which may be available now, or in the future, or never.

Promises are special, in that they allow you to do something, or wait before doing something, until some other peice of code is done. Imagine you need to write something to a database, then after successfully writing the data, let a user know the data was saved and then show the new data on the screen.

Have you ever updated a database, redirected the html back to an endpoint where your data table is displayed, only to find the table wasn't updated? Perhaps something you deleted was still there or something you added was missing? Yep, you have probably been there and felt the pain. Been there, done that.

Now, you could have worked something out using callback functions like so:

connection.query("UPDATE myTable SET ? WHERE ? LIMIT 1", [{someField: newData}, {id: id}], myCallback);

function myCallback() {
    connection.query("SELECT * FROM myTable", anotherCallBack);
}

function anotherCallBack() {
    // etc etc etc etc etc
}

You could end up with a convoluted chain of callbacks, or create some intricate set of nested callbacks. Either way, you are leading to the possiblity of more errors, writing less readable code and also less reproducible code.

Promises have the ability of cleaning up your code and allowing you to do more complex combinations of functions, not to mention handle server and database requests more efficiently.

How, then, do I write a Promise?

If you were like me, you have found the examples and tutorials online either unclear or unhelpfully complex.

Writing Promises is actually very simple.

First create a function. Let's call our function 'getData':

    function getData() {
    }

Second, add a return statement. If you don't know, a return statement allows you to stop a function and return a value to whatever called the function. Why make a return statement the first thing you write in a promise? You don't have to do it this way, but when we call this function, we will be returning a promise that allows us to chain .then() and .catch() to the function call. I'll explain that in a moment.

But what do we return? Remember when I told you a Promise is an object? Well, now we will see why. The return statement will return an object constructor for a new promise, using the new keyword. Like so:

function getData() {
    return new Promise();
}

That seems very simple. But right now, our function doesn't do anything, at least not what we want it to do, that is, to get some data. The Promise constructor takes two arguments. It is these two arguments that give Promises all their power. The arguments are two callback functions, one called resolve and the other reject. You will use these two callbacks to tell the promise what to do based on certain conditions.

resolve is our go-to, let's-get-it-on party function. You will call resolve on whatever data you received back from your function. Resolve means success.

reject is our put-on-the-brakes, something-didn't-go-right function. You will call reject on error messages or bad data. Reject means failure.

When you call a function, you want to know if it was successful or not, especially when manipulating or serving data, or calling an api and doing something in response.

In our example, let's calls an api and do something in response. I'll give two versions, one jQuery and the other Node.js (using the request npm package). Notice how I will add resolve and reject as parameters of a callback function within my Promise constructor, and then use them as callback functions within that function.


jQuery Example

function getData() {
    return new Promise((resolve, reject)=>{
        $.ajax({
            url: `http://www.omdbapi.com/?t=The+Matrix`,
            method: 'GET'
            }).done((response)=>{
                //this means my api call suceeded, so I will call resolve on the response
                resolve(response);
            }).fail((error)=>{
                //this means the api call failed, so I will call reject on the error
                reject(error);
            });
    });
}

Node.js Example

function getData() {
    return new Promise((resolve, reject)=>{
        request( `http://www.omdbapi.com/?t=The+Matrix`, (error, res, movieData)=>{
            if (error) reject(error);
            else resolve(movieData);
        });
    });
}

In each case, you are calling resolve on the data when you recieve it back successfully, and calling reject on any possible errors. But you are not done!!!

Now, you have to call the getData() function. Since it is returning a promise, you will use .then() to handle a successful call, and .catch() to hande any errors, and these will be chained to the original call. Like so:

getData()
    .then(data => console.log(data))
    .catch(error => console.log(error));

Now, of course this example doesn't do anything but log either your data or the error, but it shows what is happening. The .then() function will only run if your promise resolves data. The .catch() function will only run if your promise rejects an error. It's one or the other.

This is a very simple demonstration that may not be necessary if this was all you were doing in your Javascript. However, if you are learning promises, and you haven't used them before, let me give you a piece of advice, advice that works for any new peice of code you are learning -- anytime you are working with an asynchronous function, create a Promise based function.

You won't always do this when you are coding seriously, but the more you practice doing this, the more it will become second nature. If you finish reading this article and don't try it every time you get a chance over the next several weeks, you will struggle to learn it. Coding is a skill that is best learned by doing.

Just imagine if your getData() function received a movie title. Then you can reuse your promise multiple times in your code:

function getData(movieTitle) {
    return new Promise((resolve, reject)=>{
        request( `http://www.omdbapi.com/?t=${movieTitle}`, (error, res, movieData)=>{
            if (error) reject(error);
            else resolve(movieData);
        });
    });
}

Then, imagine you needed to get the data for all the movies in a series and you had to store this in your database? You can use something called Promise.all(), or even more fun, you can chain promises together. But those are other posts for another time. Nevertheless, if you master a single promise, you will find it much easier to understand and use all the other Promise methods. Try it out today!

Some online learning tools for Promises

Wesley L. Handy

1 post

I'm a full stack web developer who loves reading, writing, and teaching.