Node.js API compatibility - Timers

The timers module in Node.js provides a set of functions for scheduling the execution of code after a specified delay or at regular intervals. It’s essential for managing asynchronous operations and controlling the timing of function execution within applications. This module is available in the Azion Runtime through Node.js compatibility, and it’s commonly used in functions to defer work, add small delays, or coordinate the timing of asynchronous tasks with setTimeout.


Example: Basic setTimeout

The example below shows how to use the timers module in a function:

/**
* An example of using Node.js Timers API in an Azion Function.
* Support:
* - Partially supported (Extended by library `timers-browserify`)
* @module runtime-apis/nodejs/timers/main
* @example
* // Execute with Azion Bundler:
* npx edge-functions build
*
*/
import timers from "node:timers";
/**
* An example of using the Node.js Timers API in an Azion Function.
* @param {*} event
* @returns {Promise<Response>}
*/
const main = async (event) => {
console.log("Hello, world!");
console.log("Waiting for 5 seconds...");
await new Promise((resolve) => timers.setTimeout(resolve, 2000));
return new Response("Done!", { status: 200 });
};
export default main;

Example: Delayed execution with setTimeout

Schedule operations to run after a delay:

import timers from "node:timers";
import { promisify } from "node:util";
// Promisify setTimeout for async/await usage
const setTimeoutAsync = promisify(timers.setTimeout);
const main = async (event) => {
const startTime = Date.now();
const logs = [];
logs.push(`Start: ${startTime}`);
// Using promisified version - properly awaited
await setTimeoutAsync(100);
logs.push(`After 100ms delay`);
// Multiple sequential delays
await setTimeoutAsync(100);
logs.push(`After additional 100ms`);
// Calculate total time
const totalTime = Date.now() - startTime;
return new Response(JSON.stringify({
logs,
totalTimeMs: totalTime
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: setInterval for periodic operations

Execute code at regular intervals:

import timers from "node:timers";
const main = async (event) => {
const startTime = Date.now();
const ticks = [];
let tickCount = 0;
// Create interval that runs every 50ms
const intervalId = timers.setInterval(() => {
tickCount++;
const elapsed = Date.now() - startTime;
ticks.push({ tick: tickCount, elapsed });
console.log(`Tick ${tickCount} at ${elapsed}ms`);
}, 50);
// Run for 250ms then stop
await new Promise(resolve => timers.setTimeout(resolve, 250));
// Clear the interval
timers.clearInterval(intervalId);
console.log(`Total ticks: ${tickCount}`);
return new Response(JSON.stringify({
totalTicks: tickCount,
ticks,
durationMs: Date.now() - startTime
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: Immediate execution with setImmediate

Execute code immediately after the current event loop:

import timers from "node:timers";
const main = async (event) => {
const executionOrder = [];
executionOrder.push("1. Start of function");
// setImmediate runs after current code completes
timers.setImmediate(() => {
executionOrder.push("setImmediate callback");
});
// setTimeout with 0 delay still goes through timer phase
timers.setTimeout(() => {
executionOrder.push("setTimeout(0) callback");
}, 0);
// Process.nextTick runs before setImmediate (if available)
if (typeof process?.nextTick === "function") {
process.nextTick(() => {
executionOrder.push("nextTick callback");
});
}
executionOrder.push("2. End of synchronous code");
// Wait for all callbacks to execute
await new Promise(resolve => timers.setTimeout(resolve, 50));
executionOrder.push("3. After waiting");
// Note: The execution order between setImmediate and setTimeout(0)
// may vary across environments and is not guaranteed.
// In edge runtimes, this order can differ from Node.js.
return new Response(JSON.stringify({
executionOrder,
note: "Order between setImmediate and setTimeout(0) may vary"
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: Timeout with cancellation

Implement cancellable timeouts for API calls:

import timers from "node:timers";
const main = async (event) => {
const results = [];
// Create a timeout that can be cancelled
const timeoutId = timers.setTimeout(() => {
results.push("Timeout executed");
}, 500);
// Cancel the timeout before it fires
timers.setTimeout(() => {
results.push("Cancelling timeout");
timers.clearTimeout(timeoutId);
}, 200);
// Wait to see what happens
await new Promise(resolve => timers.setTimeout(resolve, 600));
// Timeout with race pattern for API calls
const fetchWithTimeout = async (url, timeoutMs) => {
const controller = new AbortController();
const timeout = timers.setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, { signal: controller.signal });
timers.clearTimeout(timeout);
return { success: true, status: response.status };
} catch (error) {
timers.clearTimeout(timeout);
return { success: false, error: error.message };
}
};
// Test with a fast-responding API
const apiResult = await fetchWithTimeout(
"https://jsonplaceholder.typicode.com/todos/1",
5000
);
results.push(`API result: ${JSON.stringify(apiResult)}`);
return new Response(JSON.stringify({ results }), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: Timer promises (timers/promises)

Use the modern promise-based timer API:

import { setTimeout, setInterval, setImmediate } from "node:timers/promises";
const main = async (event) => {
const startTime = Date.now();
const logs = [];
logs.push(`Start: ${startTime}`);
// Promise-based setTimeout
await setTimeout(100);
logs.push(`After 100ms: ${Date.now() - startTime}ms elapsed`);
// setTimeout with value
const result = await setTimeout(50, "timer result");
logs.push(`Got value: ${result}`);
// Async iterator for setInterval with proper cancellation
// Note: Use AbortController to prevent memory leaks
let count = 0;
const ac = new AbortController();
const interval = setInterval(30, undefined, { signal: ac.signal });
try {
for await (const _ of interval) {
count++;
logs.push(`Interval tick ${count}`);
if (count >= 3) {
ac.abort(); // Properly cancel the interval
break;
}
}
} catch (error) {
// AbortError is expected when we cancel
if (error.name !== "AbortError") {
throw error;
}
}
// setImmediate as promise
await setImmediate();
logs.push("After setImmediate");
// Calculate total time
const totalTime = Date.now() - startTime;
return new Response(JSON.stringify({
logs,
totalTimeMs: totalTime
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: Retry logic with exponential backoff

Implement retry patterns using timers:

import timers from "node:timers";
import { promisify } from "node:util";
const setTimeoutAsync = promisify(timers.setTimeout);
// Retry with exponential backoff
const retryWithBackoff = async (fn, maxRetries, initialDelay = 100) => {
let lastError;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const result = await fn();
return { success: true, result, attempts: attempt + 1 };
} catch (error) {
lastError = error;
if (attempt < maxRetries - 1) {
const delay = initialDelay * Math.pow(2, attempt);
console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms`);
await setTimeoutAsync(delay);
}
}
}
return { success: false, error: lastError.message, attempts: maxRetries };
};
const main = async (event) => {
// Simulate a flaky operation
let attempts = 0;
const flakyOperation = async () => {
attempts++;
if (attempts < 3) {
throw new Error(`Attempt ${attempts} failed`);
}
return `Success on attempt ${attempts}`;
};
const result = await retryWithBackoff(flakyOperation, 5, 50);
// Simulate a timeout scenario
const timeoutOperation = async () => {
await setTimeoutAsync(200);
return "This should not appear";
};
const timeoutResult = await Promise.race([
timeoutOperation(),
setTimeoutAsync(50).then(() => ({ timedOut: true }))
]);
return new Response(JSON.stringify({
retryResult: result,
timeoutResult
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Supported APIs

APIStatus
setTimeout()🟢 Supported
clearTimeout()🟢 Supported
setInterval()🟢 Supported
clearInterval()🟢 Supported
setImmediate()🟢 Supported
clearImmediate()🟢 Supported
timers/promises.setTimeout()🟢 Supported
timers/promises.setInterval()🟢 Supported
timers/promises.setImmediate()🟢 Supported
timers.active()🟡 Partially supported
timers.enroll()🔴 Not supported
timers.unenroll()🔴 Not supported
timers.getActive()🟡 Partially supported