Build a JavaScript Promise | Skilled.dev
Interview Question

Build a JavaScript Promise

Loading...

Building a JavaScript Promise implementation has become an increasingly popular interview question. It tests your understanding of asynchronous JS and promises at a fundamental level. It also shows you can effectively build objects and implement powerful patterns like chaining.

Asynchronous programming is a core concept in JavaScript and is a feature that gives JavaScript a lot of speed compared to other scripted programming languages. JavaScript is single-threaded which means it executes programs line-by-line. It is also asynchronous which means that if our program execution reaches a block of code that must wait on a result, it will continue on past this block of code that is waiting so the program doesn't freeze execution, and once that async task finishes, our code will handle the result it was waiting for by using a promise or a callback.

Since the release of ES2015, the most common way to handle the result of an async function call is through a Promise, but before that callbacks were used. Recently, the async/await syntax was added to JavaScript, but this is just an abstraction on top of promises, and we'll see how they compare at the end of the article.

In this lesson, you will learn JavaScript promises by building a JavaScript promise implementation from scratch. Your promise will be declared exactly like they are in native JavaScript new Promise(...), and it will be able to chain .then() and .catch() statements to handle the result of async code.

If the below problem prompt is confusing and seems too complex, don't worry because it will all make sense as you follow the solution.

Create a class named PromiseSimple that allows you to create an object to handle asynchronous actions using the then and catch keywords which should also be chainable. Your constructor will take a function as an argument that will resolve or reject the async function request new PromiseSimple((resolve, reject) => {}) which triggers the promise chain.

 

Implement a Promise

NOTE: If you want to see our promise implementation working with a real API request, check out the REPL from the solution video.

The JavaScript promise example we are building is meant to help you understand the fundamentals of promises and asynchronous thinking — it is not intended to show the most optimized version of a promise. I will first describe promises for beginners and then dive into our own promise implementation so we can understand it from the ground up.

You've probably seen something like this before:

 

The block of code in the .then() waits until it receives the response from the server before it executes anything. This is called a Promise. But don't let the fancy name or the fact that there is asynchronous code intimidate you — a Promise is just a plain old JavaScript object containing methods that allow you to execute code to handle the response in-order after the promise resolves.

 

Let me reiterate (because this is something that was difficult for me to grasp when I first learned promises), a Promise is just an object.

To be able to wait on the server's response and execute the code in the .then() chain after the response, you MUST return a Promise object. This is not something functions get out of the box. Behind the scenes, the fetch function is doing something like this.

 

The fetch() function makes an http request to the server, but the client doesn't know when the server will send back the results. So JavaScript begins executing other unrelated code while waiting on the server to return with the response. Once the client receives the response, it triggers the execution of the code in the .then() statements by calling resolve(apiResponse).

Now let's take a closer look at how the Promise actually allows you to do this.

 

NOTE: This version of a Promise is for educational purposes only. I've left out some of the more advanced features and distilled it to its core functionality.

I've named it PromiseSimple so it won't clash with the native Promise in case you want to copy and paste it into your Chrome console. Our promise implementation has a constructor, 2 public methods that you may be familiar with then() and catch(), and 2 internal methods onResolve() and onReject().

When you create a promise, you do so like this new Promise((resolve, reject) => {/* ... */}). You pass it a callback function which I've named executionFunction in the constructor. The execution function takes a resolve and reject which map to the internal onResolve() and onReject() function.

The constructor also creates a promiseChain array and handleError function. When a series of .then(() => {}) are added by the developer, it pushes each handleSuccess function onto the promiseChain.

When a developer calls catch(() => {}), it assigns the function to the internal handleError.

Notice that the then() and catch() function return this;. This allows you to chain multiple then()'s since you are returning the object itself.

NOTE: In the native Promise, these then() and catch() functions actually return a new Promise themselves, but for this simple scenario, I've only returned this. In addition, there can be multiple .catch() blocks, and they can be chained as well and aren't required to come at the end of the .then() chain.

When your asynchronous function calls resolve(apiResponse), the promise object then begins executing onResolve(apiResponse). It iterates through the entire promiseChain by removing the function at the front and executes it with the most recent value saved in storedValue. It then updates storedValue to the result of the most recent execution. It will execute these functions in order. This creates the synchronous promise chain.

This loop is wrapped in a try/catch block. This is special syntax that looks for errors. If your asynchronous function calls reject(error) or your try/catch recognizes an error, it will then be passed to the onReject() method which calls the function that you passed to .catch().

NOTE: If you want to see our promise implementation working with a real API request, check out the REPL from the solution video.

Putting it all together with a more practical example:

 

async/await

The async/await syntax is just a wrapper around promises. If you mark a function as async, it just converts the return response to a promise.

 

This is the equivalent of doing the following:

 
Loading...

Table of Contents