Discover Promises in Node.js
A Promise is a special object in JavaScript that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Essentially, a Promise is a placeholder for a value that is not yet available but will be in the future.
Think of a Promise like ordering a pizza: you don't get it right away, but the delivery person promises to bring it to you later. You don't know exactly when, but you know the outcome will either be "pizza delivered" or "something went wrong."
Promise States
A Promise can be in one of three states:
- Pending: The initial state, where the asynchronous operation is still running.
- Fulfilled: The operation completed successfully, and the Promise is now resolved with a value.
- Rejected: The operation failed, and the Promise is settled with a reason (usually an error).
When you order the pizza, you're in the pending state, hungry and hopeful. If the pizza arrives hot and cheesy, you've entered the fulfilled state. But if the restaurant calls to say they've dropped your pizza on floor, you're in the rejected state.
Regardless of whether your dinner ends in joy or disappointment, once there's a final outcome, the Promise is considered settled.
Basic Syntax of a Promise
One of the most common ways to create a Promise is using the new Promise()
constructor. The constructor takes a function with two parameters: resolve
and reject
. These functions are used to transition the Promise from the pending state to either fulfilled or rejected.
If an error is thrown inside the executor function, the Promise will be rejected with that error.
The return value of the executor function is ignored: only resolve
or reject
should be used to settle the Promise.
const const myPromise: Promise<any>
myPromise = new var Promise: PromiseConstructor
new <any>(executor: (resolve: (value: any) => void, reject: (reason?: any) => void) => void) => Promise<any>
Promise((resolve: (value: any) => void
resolve, reject: (reason?: any) => void
reject) => {
const const success: true
success = true;
if (const success: true
success) {
resolve: (value: any) => void
resolve('Operation was successful!');
} else {
reject: (reason?: any) => void
reject('Something went wrong.');
}
});
In the above example:
- If the
success
condition istrue
, the Promise is fulfilled and the value'Operation was successful!'
is passed to theresolve
function. - If the
success
condition isfalse
, the Promise is rejected and the error'Something went wrong.'
is passed to thereject
function.
Handling Promises with .then()
, .catch()
, and .finally()
Once a Promise is created, you can handle the outcome by using the .then()
, .catch()
, and .finally()
methods.
.then()
is used to handle a fulfilled Promise and access its result..catch()
is used to handle a rejected Promise and catch any errors that may occur..finally()
is used to handle a settled Promise, regardless of whether the Promise resolved or rejected.
const const myPromise: Promise<any>
myPromise = new var Promise: PromiseConstructor
new <any>(executor: (resolve: (value: any) => void, reject: (reason?: any) => void) => void) => Promise<any>
Promise((resolve: (value: any) => void
resolve, reject: (reason?: any) => void
reject) => {
const const success: true
success = true;
if (const success: true
success) {
resolve: (value: any) => void
resolve('Operation was successful!');
} else {
reject: (reason?: any) => void
reject('Something went wrong.');
}
});
const myPromise: Promise<any>
myPromise
.Promise<any>.then<void, never>(onfulfilled?: ((value: any) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(result: any
result => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result: any
result); // This will run if the Promise is fulfilled
})
.Promise<void>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
catch(error: any
error => {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error(error: any
error); // This will run if the Promise is rejected
})
.Promise<void>.finally(onfinally?: (() => void) | null | undefined): Promise<void>
finally(() => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('The promise has completed'); // This will run when the Promise is settled
});
Chaining Promises
One of the great features of Promises is that they allow you to chain multiple asynchronous operations together. When you chain Promises, each .then()
block waits for the previous one to complete before it runs.
const { function setTimeout<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
setTimeout: function delay<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
delay } = var require: NodeJS.Require
(id: string) => any
require('node:timers/promises');
const const promise: Promise<string>
promise = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(1000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'First task completed');
const promise: Promise<string>
promise
.Promise<string>.then<string, never>(onfulfilled?: ((value: string) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(result: string
result => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result: string
result); // 'First task completed'
return delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(1000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'Second task completed'); // Return a second Promise
})
.Promise<string>.then<void, never>(onfulfilled?: ((value: string) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(result: string
result => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result: string
result); // 'Second task completed'
})
.Promise<void>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
catch(error: any
error => {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error(error: any
error); // If any Promise is rejected, catch the error
});
Using Async/Await with Promises
One of the best ways to work with Promises in modern JavaScript is using async/await. This allows you to write asynchronous code that looks synchronous, making it much easier to read and maintain.
async
is used to define a function that returns a Promise.await
is used inside anasync
function to pause execution until a Promise settles.
async function function performTasks(): Promise<void>
performTasks() {
try {
const const result1: any
result1 = await promise1;
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(const result1: any
result1); // 'First task completed'
const const result2: any
result2 = await promise2;
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(const result2: any
result2); // 'Second task completed'
} catch (function (local var) error: unknown
error) {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error(function (local var) error: unknown
error); // Catches any rejection or error
}
}
function performTasks(): Promise<void>
performTasks();
In the performTasks
function, the await
keyword ensures that each Promise is settled before moving on to the next statement. This leads to a more linear and readable flow of asynchronous code.
Essentially, the code above will execute the same as if the user wrote:
promise1
.then(function (result1: any
result1) {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result1: any
result1);
return promise2;
})
.then(function (result2: any
result2) {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result2: any
result2);
})
.catch(function (error: any
error) {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(error: any
error);
});
Top-Level Await
When using ECMAScript Modules, the module itself is treated as a top-level scope that supports asynchronous operations natively. This means that you can use await
at the top level without needing an async
function.
import { function setTimeout<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
setTimeout as function delay<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
delay } from 'node:timers/promises';
await delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(1000);
Async/await can be much more intricate than the simple examples provided. James Snell, a member of the Node.js Technical Steering Committee, has an in-depth presentation that explores the complexities of Promises and async/await.
Promise-based Node.js APIs
Node.js provides Promise-based versions of many of its core APIs, especially in cases where asynchronous operations were traditionally handled with callbacks. This makes it easier to work with Node.js APIs and Promises, and reduces the risk of "callback hell."
For example, the fs
(file system) module has a Promise-based API under fs.promises
:
const module "node:fs/promises"
fs = var require: NodeJS.Require
(id: string) => any
require('node:fs').module "node:fs/promises"
export promises
promises;
// Or, you can import the promisified version directly:
// const fs = require('node:fs/promises');
async function function readFile(): Promise<void>
readFile() {
try {
const const data: string
data = await module "node:fs/promises"
fs.function readFile(path: PathLike | fs.FileHandle, options: ({
encoding: BufferEncoding;
flag?: OpenMode | undefined;
} & EventEmitter<T extends EventMap<T> = DefaultEventMap>.Abortable) | BufferEncoding): Promise<string> (+2 overloads)
readFile('example.txt', 'utf8');
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(const data: string
data);
} catch (function (local var) err: unknown
err) {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error('Error reading file:', function (local var) err: unknown
err);
}
}
function readFile(): Promise<void>
readFile();
In this example, fs.readFile()
returns a Promise, which we handle using async/await
syntax to read the contents of a file asynchronously.
Advanced Promise Methods
JavaScript's Promise
global provides several powerful methods that help manage multiple asynchronous tasks more effectively:
Promise.all()
This method accepts an array of Promises and returns a new Promise that resolves once all the Promises are fulfilled. If any Promise is rejected, Promise.all()
will immediately reject. However, even if rejection occurs, the Promises continue to execute. When handling a large number of Promises, especially in batch processing, using this function can strain the system's memory.
const { function setTimeout<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
setTimeout: function delay<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
delay } = var require: NodeJS.Require
(id: string) => any
require('node:timers/promises');
const const fetchData1: Promise<string>
fetchData1 = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(1000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'Data from API 1');
const const fetchData2: Promise<string>
fetchData2 = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(2000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'Data from API 2');
var Promise: PromiseConstructor
Promise.PromiseConstructor.all<[Promise<string>, Promise<string>]>(values: [Promise<string>, Promise<string>]): Promise<[string, string]> (+1 overload)
all([const fetchData1: Promise<string>
fetchData1, const fetchData2: Promise<string>
fetchData2])
.Promise<[string, string]>.then<void, never>(onfulfilled?: ((value: [string, string]) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(results: [string, string]
results => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(results: [string, string]
results); // ['Data from API 1', 'Data from API 2']
})
.Promise<void>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
catch(error: any
error => {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error('Error:', error: any
error);
});
Promise.allSettled()
This method waits for all promises to either resolve or reject and returns an array of objects that describe the outcome of each Promise.
const const promise1: Promise<string>
promise1 = var Promise: PromiseConstructor
Promise.PromiseConstructor.resolve<string>(value: string): Promise<string> (+2 overloads)
resolve('Success');
const const promise2: Promise<never>
promise2 = var Promise: PromiseConstructor
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
reject('Failed');
var Promise: PromiseConstructor
Promise.PromiseConstructor.allSettled<[Promise<string>, Promise<never>]>(values: [Promise<string>, Promise<never>]): Promise<[PromiseSettledResult<string>, PromiseSettledResult<...>]> (+1 overload)
allSettled([const promise1: Promise<string>
promise1, const promise2: Promise<never>
promise2]).Promise<[PromiseSettledResult<string>, PromiseSettledResult<never>]>.then<void, never>(onfulfilled?: ((value: [PromiseSettledResult<string>, PromiseSettledResult<never>]) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<...>) | ... 1 more ... | undefined): Promise<...>
then(results: [PromiseSettledResult<string>, PromiseSettledResult<never>]
results => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(results: [PromiseSettledResult<string>, PromiseSettledResult<never>]
results);
// [ { status: 'fulfilled', value: 'Success' }, { status: 'rejected', reason: 'Failed' } ]
});
Unlike Promise.all()
, Promise.allSettled()
does not short-circuit on failure. It waits for all promises to settle, even if some reject. This provides better error handling for batch operations, where you may want to know the status of all tasks, regardless of failure.
Promise.race()
This method resolves or rejects as soon as the first Promise settles, whether it resolves or rejects. Regardless of which promise settles first, all promises are fully executed.
const { function setTimeout<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
setTimeout: function delay<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
delay } = var require: NodeJS.Require
(id: string) => any
require('node:timers/promises');
const const task1: Promise<string>
task1 = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(2000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'Task 1 done');
const const task2: Promise<string>
task2 = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(1000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'Task 2 done');
var Promise: PromiseConstructor
Promise.PromiseConstructor.race<[Promise<string>, Promise<string>]>(values: [Promise<string>, Promise<string>]): Promise<string> (+1 overload)
race([const task1: Promise<string>
task1, const task2: Promise<string>
task2]).Promise<string>.then<void, never>(onfulfilled?: ((value: string) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(result: string
result => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result: string
result); // 'Task 2 done' (since task2 finishes first)
});
Promise.any()
This method resolves as soon as one of the Promises resolves. If all promises are rejected, it will reject with an AggregateError
.
const { function setTimeout<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
setTimeout: function delay<T = void>(delay?: number, value?: T, options?: TimerOptions): Promise<T>
delay } = var require: NodeJS.Require
(id: string) => any
require('node:timers/promises');
const const api1: Promise<string>
api1 = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(2000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'API 1 success');
const const api2: Promise<string>
api2 = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(1000).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'API 2 success');
const const api3: Promise<string>
api3 = delay<void>(delay?: number, value?: void | undefined, options?: TimerOptions): Promise<void>
delay(1500).Promise<void>.then<string, never>(onfulfilled?: ((value: void) => string | PromiseLike<string>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(() => 'API 3 success');
var Promise: PromiseConstructor
Promise.PromiseConstructor.any<[Promise<string>, Promise<string>, Promise<string>]>(values: [Promise<string>, Promise<string>, Promise<string>]): Promise<...> (+1 overload)
any([const api1: Promise<string>
api1, const api2: Promise<string>
api2, const api3: Promise<string>
api3])
.Promise<string>.then<void, never>(onfulfilled?: ((value: string) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(result: string
result => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result: string
result); // 'API 2 success' (since it resolves first)
})
.Promise<void>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
catch(error: any
error => {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error('All promises rejected:', error: any
error);
});
Promise.reject()
and Promise.resolve()
These methods create a rejected or resolved Promise directly.
var Promise: PromiseConstructor
Promise.PromiseConstructor.resolve<string>(value: string): Promise<string> (+2 overloads)
resolve('Resolved immediately').Promise<string>.then<void, never>(onfulfilled?: ((value: string) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(result: string
result => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result: string
result); // 'Resolved immediately'
});
Promise.try()
Promise.try()
is a method that executes a given function, whether it's synchronous or asynchronous, and wraps the result in a promise. If the function throws an error or returns a rejected promise, Promise.try()
will return a rejected promise. If the function completes successfully, the returned promise will be fulfilled with its value.
This can be particularly useful for starting promise chains in a consistent way, especially when working with code that might throw errors synchronously.
function function mightThrow(): string
mightThrow() {
if (var Math: Math
Math.Math.random(): number
random() > 0.5) {
throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error('Oops, something went wrong!');
}
return 'Success!';
}
var Promise: PromiseConstructor
Promise.PromiseConstructor.try<string, []>(callbackFn: () => string | PromiseLike<string>): Promise<string>
try(function mightThrow(): string
mightThrow)
.Promise<string>.then<void, never>(onfulfilled?: ((value: string) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(result: string
result => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Result:', result: string
result);
})
.Promise<void>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
catch(err: any
err => {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error('Caught error:', err: any
err.message);
});
In this example, Promise.try()
ensures that if mightThrow()
throws an error, it will be caught in the .catch()
block, making it easier to handle both sync and async errors in one place.
Promise.withResolvers()
This method creates a new promise along with its associated resolve and reject functions, and returns them in a convenient object. This is used, for example, when you need to create a promise but resolve or reject it later from outside the executor function.
const { const promise: Promise<any>
promise, const resolve: (value: any) => void
resolve, const reject: (reason?: any) => void
reject } = var Promise: PromiseConstructor
Promise.PromiseConstructor.withResolvers<any>(): PromiseWithResolvers<any>
withResolvers();
function setTimeout<[]>(callback: () => void, delay?: number): NodeJS.Timeout (+2 overloads)
setTimeout(() => {
const resolve: (value: any) => void
resolve('Resolved successfully!');
}, 1000);
const promise: Promise<any>
promise.Promise<any>.then<void, never>(onfulfilled?: ((value: any) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
then(value: any
value => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Success:', value: any
value);
});
In this example, Promise.withResolvers()
gives you full control over when and how the promise is resolved or rejected, without needing to define the executor function inline. This pattern is commonly used in event-driven programming, timeouts, or when integrating with non-promise-based APIs.
Error Handling with Promises
Handling errors in Promises ensures your application behaves correctly in case of unexpected situations.
- You can use
.catch()
to handle any errors or rejections that occur during the execution of Promises.
myPromise
.then(result: any
result => var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(result: any
result))
.catch(error: any
error => var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error(error: any
error)) // Handles the rejection
.finally(error: any
error => var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Promise completed')); // Runs regardless of promise resolution
- Alternatively, when using
async/await
, you can use atry/catch
block to catch and handle errors.
async function function performTask(): Promise<void>
performTask() {
try {
const const result: any
result = await myPromise;
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log(const result: any
result);
} catch (function (local var) error: unknown
error) {
var console: Console
console.Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)
error(function (local var) error: unknown
error); // Handles any errors
} finally {
// This code is executed regardless of failure
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('performTask() completed');
}
}
function performTask(): Promise<void>
performTask();
Scheduling Tasks in the Event Loop
In addition to Promises, Node.js provides several other mechanisms for scheduling tasks in the event loop.
queueMicrotask()
queueMicrotask()
is used to schedule a microtask, which is a lightweight task that runs after the currently executing script but before any other I/O events or timers. Microtasks include tasks like Promise resolutions and other asynchronous operations that are prioritized over regular tasks.
function queueMicrotask(callback: () => void): void (+1 overload)
queueMicrotask(() => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Microtask is executed');
});
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Synchronous task is executed');
In the above example, "Microtask is executed" will be logged after "Synchronous task is executed," but before any I/O operations like timers.
process.nextTick()
process.nextTick()
is used to schedule a callback to be executed immediately after the current operation completes. This is useful for situations where you want to ensure that a callback is executed as soon as possible, but still after the current execution context.
var process: NodeJS.Process
process.NodeJS.Process.nextTick(callback: Function, ...args: any[]): void
nextTick(() => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Next tick callback');
});
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Synchronous task executed');
setImmediate()
setImmediate()
schedules a callback to be executed in the check phase of the Node.js event loop, which runs after the poll phase, where most I/O callbacks are processed.
function setImmediate<[]>(callback: () => void): NodeJS.Immediate (+1 overload)
setImmediate(() => {
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Immediate callback');
});
var console: Console
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
log('Synchronous task executed');
When to Use Each
- Use
queueMicrotask()
for tasks that need to run immediately after the current script and before any I/O or timer callbacks, typically for Promise resolutions. - Use
process.nextTick()
for tasks that should execute before any I/O events, often useful for deferring operations or handling errors synchronously. - Use
setImmediate()
for tasks that should run after the poll phase, once most I/O callbacks have been processed.
Because these tasks execute outside of the current synchronous flow, uncaught exceptions inside these callbacks won't be caught by surrounding try/catch
blocks and may crash the application if not properly managed (e.g., by attaching .catch()
to Promises or using global error handlers like process.on('uncaughtException')
).
For more information on the Event Loop, and the execution order of various phases, please see the related article, The Node.js Event Loop.