Compatibilidade APIs Node.js - Timers

O módulo timers no Node.js fornece um conjunto de funções para agendar a execução de código após um atraso especificado ou em intervalos regulares. É essencial para gerenciar operações assíncronas e controlar o tempo de execução de funções dentro de aplicações. Este módulo está disponível no Azion Runtime através da compatibilidade com Node.js, sendo comumente usado em functions para adiar trabalho, adicionar pequenos atrasos ou coordenar o tempo de tarefas assíncronas com setTimeout.


Exemplo: setTimeout básico

O exemplo abaixo mostra como usar o módulo timers em uma 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;

Exemplo: Execução adiada com setTimeout

Agende operações para executar após um atraso:

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;

Exemplo: setInterval para operações periódicas

Execute código em intervalos regulares:

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;

Exemplo: Execução imediata com setImmediate

Execute código imediatamente após o event loop atual:

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;

Exemplo: Timeout com cancelamento

Implemente timeouts canceláveis para chamadas de API:

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;

Exemplo: Promises de timer (timers/promises)

Use a API moderna de timer baseada em promises:

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;

Exemplo: Lógica de retry com backoff exponencial

Implemente padrões de retry usando 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;

APIs com suporte

APIStatus
setTimeout()🟢 Com suporte
clearTimeout()🟢 Com suporte
setInterval()🟢 Com suporte
clearInterval()🟢 Com suporte
setImmediate()🟢 Com suporte
clearImmediate()🟢 Com suporte
timers/promises.setTimeout()🟢 Com suporte
timers/promises.setInterval()🟢 Com suporte
timers/promises.setImmediate()🟢 Com suporte
timers.active()🟡 Parcialmente suportado
timers.enroll()🔴 Sem suporte
timers.unenroll()🔴 Sem suporte
timers.getActive()🟡 Parcialmente suportado

Recursos relacionados