Promises

The built-in Promise object provides a unified interface for managing asynchronous tasks.

There are many situations where a JavaScript program will have to pause for an unknown duration of time before it can continue working, like waiting on a response from a database or the result of running an external program. In the early days of JavaScript, programmers relied on callback functions to manage these kinds of asynchronous tasks.

JavaScript with callbacks is hard to get right intuitively. A lot of code ends up looking like this:

Callbacks also introduce a potential source of bugs and memory leaks with variable scoping, where a variable with the same name is defined multiple times in nested closures.

The use of Promise objects, along with the built-in keywords async and await, allow programmers to order sequential instructions for handling asynchronous tasks. It is common for TypeScript libraries and built-in Node.js modules to support a Promise-based approach to writing programs.

The Promise object

A common way to create a Promise is by constructing it with new Promise(...).

A Promise object must be initialized with a function that takes two parameters, which are often labeled resolve and reject (although you could call them success and failure, done and failed, etc).

Arrow functionAlternate parameter name
new Promise(function(resolve, reject) { ... })

This function is called immediately when the Promise is constructed. The arguments passed to resolve and reject are each functions which accept a single parameter.

Arrow functionAlternate parameter name
new Promise((
    
resolve: (value: any) => any,
    
reject: (error: any) => any,
) => { ... })

If resolve is called first, then the Promise object uses the value argument as the final result of the asynchronous task it represents. If reject is called first, then the Promise object enters an "error state" where it will produce the error instead.

then and catch

Once the Promise is created, you can use its then and catch methods to register callback functions that should be executed with the result of resolve and reject respectively. Try modifying the simple example below:

Loading TypeScript...

The Promise will only call one callback function exactly once - the function registered with then, or the function registered with catch. Each of these function calls returns a new Promise which represents the result of performing some further (possibly asynchronous) work.

If either function returns a value, that value will be passed to subsequent callback functions registered with then or catch.

Loading TypeScript...

Resolve and reject

The Promise.resolve and Promise.reject functions create Promise objects that immediately resolve or reject with the given values.

It's a useful shorthand for writing a full function to initialize a Promise object and immediately call resolve or reject with a particular value.

The benefit of doing this, even for synchronous function that don't depend on asynchronous result, is that you can now use the function in a configurable chain of transformations that can include both synchronous and asynchronous work.

Loading TypeScript...

Async and await

The async keyword indicates that a function returns a Promise.

If the return type is not specified, TypeScript will attempt to infer the type of the returned Promise. If the function is missing type specifications, the return type will default to Promise<any>, or Promise<void> if the function does not return anything.

Asynchronous function
async function getResultAsync(): Promise<any> { ... }

One of the key advantages to using Promises is the ability to use async and await.

Loading TypeScript...

async functions

An async function must return a correctly-typed Promise object.

Loading TypeScript...

Was this page helpful?