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 usageconst 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 backoffconst 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
| API | Status |
|---|---|
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 |