Skip to main content Skip to docs navigation

Promise API

Learn how to implement APIs that return promises in JavaScript.

On this page

How to implement a promise-based API

In the last article we discussed how to use APIs that return promises. In this article we'll look at the other side — how to implement APIs that return promises. This is a much less common task than using promise-based APIs, but it's still worth knowing about.

Prerequisites: A reasonable understanding of JavaScript fundamentals, including event handling and the basics of promises.
Objective: To understand how to implement promise-based APIs.

Generally, when you implement a promise-based API, you'll be wrapping an asynchronous operation, which might use events, or plain callbacks, or a message-passing model. You'll arrange for a Promise object to handle the success or failure of that operation properly.

Implementing an alarm() API

In this example we'll implement a promise-based alarm API, called alarm() . It will take as arguments the name of the person to wake up and a delay in milliseconds to wait before waking the person up. After the delay, the function will send a "Wake up!" message, including the name of the person we need to wake up.

Wrapping setTimeout()

We'll use the setTimeout() API to implement our alarm() function. The setTimeout() API takes as arguments a callback function and a delay, given in milliseconds. When setTimeout() is called, it starts a timer set to the given delay, and when the time expires, it calls the given function.

In the example below, we call setTimeout() with a callback function and a delay of 1000 milliseconds:

html
                                        
                                            
                                                
                                                    <
                                                    button
                                                
                                                id
                                                
                                                    =
                                                    "
                                                    set-alarm"
                                                
                                                >
                                            
                                            Set alarm
                                            
                                                
                                                    </
                                                    button
                                                
                                                >
                                            
                                            
                                                
                                                    <
                                                    div
                                                
                                                id
                                                
                                                    =
                                                    "
                                                    output"
                                                
                                                >
                                            
                                            
                                                
                                                    </
                                                    div
                                                
                                                >
                                            
                                        
                                    
js
                                        
                                            const
                                            output =
                                            document.
                                            querySelector
                                            (
                                            "#output"
                                            )
                                            ;
                                            const
                                            button =
                                            document.
                                            querySelector
                                            (
                                            "#set-alarm"
                                            )
                                            ;
                                            function
                                            setAlarm
                                            (
                                            )
                                            {
                                            setTimeout
                                            (
                                            (
                                            )
                                            =>
                                            {
                                            output.
                                            textContent =
                                            "Wake up!"
                                            ;
                                            }
                                            ,
                                            1000
                                            )
                                            ;
                                            }
                                            button.
                                            addEventListener
                                            (
                                            "click"
                                            ,
                                            setAlarm)
                                            ;
                                        
                                    

The Promise() constructor

Our alarm() function will return a Promise that is fulfilled when the timer expires. It will pass a "Wake up!" message into the then() handler, and will reject the promise if the caller supplies a negative delay value.

The key component here is the Promise() constructor. The Promise() constructor takes a single function as an argument. We'll call this function the executor . When you create a new promise you supply the implementation of the executor.

This executor function itself takes two arguments, which are both also functions, and which are conventionally called resolve and reject . In your executor implementation, you call the underlying asynchronous function. If the asynchronous function succeeds, you call resolve , and if it fails, you call reject . If the executor function throws an error, reject is called automatically. You can pass a single parameter of any type into resolve and reject .

So we can implement alarm() like this:

js
                                        
                                            function
                                            alarm
                                            (
                                            
                                                person,
                                                delay
                                            
                                            )
                                            {
                                            return
                                            new
                                            Promise
                                            (
                                            (
                                            
                                                resolve,
                                                reject
                                            
                                            )
                                            =>
                                            {
                                            if
                                            (
                                            delay <
                                            0
                                            )
                                            {
                                            throw
                                            new
                                            Error
                                            (
                                            "Alarm delay must not be negative"
                                            )
                                            ;
                                            }
                                            setTimeout
                                            (
                                            (
                                            )
                                            =>
                                            {
                                            resolve
                                            (
                                            
                                                `
                                                Wake up, 
                                                
                                                    ${
                                                    person}
                                                
                                                !
                                                `
                                            
                                            )
                                            ;
                                            }
                                            ,
                                            delay)
                                            ;
                                            }
                                            )
                                            ;
                                            }
                                        
                                    

This function creates and returns a new Promise . Inside the executor for the promise, we:

  • check that delay is not negative, and throw an error if it is.
  • call setTimeout() , passing a callback and delay . The callback will be called when the timer expires, and in the callback we call resolve , passing in our "Wake up!" message.

Using the alarm() API

This part should be quite familiar from the last article. We can call alarm() , and on the returned promise call then() and catch() to set handlers for promise fulfillment and rejection.

js
                                        
                                            const
                                            name =
                                            document.
                                            querySelector
                                            (
                                            "#name"
                                            )
                                            ;
                                            const
                                            delay =
                                            document.
                                            querySelector
                                            (
                                            "#delay"
                                            )
                                            ;
                                            const
                                            button =
                                            document.
                                            querySelector
                                            (
                                            "#set-alarm"
                                            )
                                            ;
                                            const
                                            output =
                                            document.
                                            querySelector
                                            (
                                            "#output"
                                            )
                                            ;
                                            function
                                            alarm
                                            (
                                            
                                                person,
                                                delay
                                            
                                            )
                                            {
                                            return
                                            new
                                            Promise
                                            (
                                            (
                                            
                                                resolve,
                                                reject
                                            
                                            )
                                            =>
                                            {
                                            if
                                            (
                                            delay <
                                            0
                                            )
                                            {
                                            throw
                                            new
                                            Error
                                            (
                                            "Alarm delay must not be negative"
                                            )
                                            ;
                                            }
                                            setTimeout
                                            (
                                            (
                                            )
                                            =>
                                            {
                                            resolve
                                            (
                                            
                                                `
                                                Wake up, 
                                                
                                                    ${
                                                    person}
                                                
                                                !
                                                `
                                            
                                            )
                                            ;
                                            }
                                            ,
                                            delay)
                                            ;
                                            }
                                            )
                                            ;
                                            }
                                            button.
                                            addEventListener
                                            (
                                            "click"
                                            ,
                                            (
                                            )
                                            =>
                                            {
                                            alarm
                                            (
                                            name.
                                            value,
                                            delay.
                                            value)
                                            .
                                            then
                                            (
                                            (
                                            message
                                            )
                                            =>
                                            (
                                            output.
                                            textContent =
                                            message)
                                            )
                                            .
                                            catch
                                            (
                                            (
                                            error
                                            )
                                            =>
                                            (
                                            output.
                                            textContent =
                                            
                                                `
                                                Couldn't set alarm: 
                                                
                                                    ${
                                                    error}
                                                
                                                `
                                            
                                            )
                                            )
                                            ;
                                            }
                                            )
                                            ;
                                        
                                    

Try setting different values for "Name" and "Delay". Try setting a negative value for "Delay".

Using async and await with the alarm() API

Since alarm() returns a Promise , we can do everything with it that we could do with any other promise: promise chaining, Promise.all() , and async / await :

js
                                        
                                            const
                                            name =
                                            document.
                                            querySelector
                                            (
                                            "#name"
                                            )
                                            ;
                                            const
                                            delay =
                                            document.
                                            querySelector
                                            (
                                            "#delay"
                                            )
                                            ;
                                            const
                                            button =
                                            document.
                                            querySelector
                                            (
                                            "#set-alarm"
                                            )
                                            ;
                                            const
                                            output =
                                            document.
                                            querySelector
                                            (
                                            "#output"
                                            )
                                            ;
                                            function
                                            alarm
                                            (
                                            
                                                person,
                                                delay
                                            
                                            )
                                            {
                                            return
                                            new
                                            Promise
                                            (
                                            (
                                            
                                                resolve,
                                                reject
                                            
                                            )
                                            =>
                                            {
                                            if
                                            (
                                            delay <
                                            0
                                            )
                                            {
                                            throw
                                            new
                                            Error
                                            (
                                            "Alarm delay must not be negative"
                                            )
                                            ;
                                            }
                                            setTimeout
                                            (
                                            (
                                            )
                                            =>
                                            {
                                            resolve
                                            (
                                            
                                                `
                                                Wake up, 
                                                
                                                    ${
                                                    person}
                                                
                                                !
                                                `
                                            
                                            )
                                            ;
                                            }
                                            ,
                                            delay)
                                            ;
                                            }
                                            )
                                            ;
                                            }
                                            button.
                                            addEventListener
                                            (
                                            "click"
                                            ,
                                            async
                                            (
                                            )
                                            =>
                                            {
                                            try
                                            {
                                            const
                                            message =
                                            await
                                            alarm
                                            (
                                            name.
                                            value,
                                            delay.
                                            value)
                                            ;
                                            output.
                                            textContent =
                                            message;
                                            }
                                            catch
                                            (
                                            error)
                                            {
                                            output.
                                            textContent =
                                            
                                                `
                                                Couldn't set alarm: 
                                                
                                                    ${
                                                    error}
                                                
                                                `
                                            
                                            ;
                                            }
                                            }
                                            )
                                            ;
                                        
                                    

See also

Updated on April 20, 2024 by Datarist.