Contrairement aux langages de programmation traditionnels, Node.js ne propose pas de fonction sleep() intégrée en raison
de sa nature asynchrone. Cependant, il existe plusieurs façons efficaces d’implémenter des fonctions d’attente et
de pause dans Node.js. Ce guide explore 4 méthodes différentes pour suspendre l’exécution, de la simple setTimeout() aux solutions
modernes basées sur Promises. Que vous ayez besoin d’appliquer une limitation de débit, de simuler des délais ou
de créer des boucles basées sur le temps, comprendre ces patterns de pause dans Node.js vous aidera à écrire un
code plus efficace et plus maintenable.
Pourquoi avoir besoin de dormir dans Node.js ?
La fonctionnalité de pause dans Node.js est essentielle dans divers scénarios où vous devez suspendre l’exécution pendant une durée précise. Les cas d’usage courants incluent :
- Limitation du débit : faire une pause entre les appels API pour éviter d’atteindre les limites
- Tests : simuler des délais réels pendant le développement et les tests
- Logique de retry : attendre avant de réessayer des opérations échouées
- Polling : créer des intervalles entre les vérifications d’état
- Expérience utilisateur : ajouter des délais pour une meilleure UX dans les applications CLI
Méthode 1 : utiliser setTimeout()
La façon la plus simple d’implémenter une pause dans Node.js consiste à utiliser setTimeout(). Cette
méthode planifie l’exécution d’un callback après un nombre de millisecondes donné, mais ne bloque pas l’exécution
du code suivant.
// Basic setTimeout sleep function
function sleep(ms, callback) {
setTimeout(callback, ms);
}
console.log('Start');
sleep(2000, () => {
console.log('End after 2 seconds');
});
console.log('This runs immediately');
Avantages : simple et largement pris en charge
Inconvénients : peut mener au callback hell avec des opérations asynchrones complexes
Méthode 2 : pause basée sur Promise
La manière la plus populaire et la plus moderne d’implémenter une pause dans Node.js consiste à utiliser des
Promises avec setTimeout().
Cela vous permet d’utiliser la syntaxe async/await pour un code plus propre et plus lisible.
// Promise-based sleep function
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// Using async/await
async function demo() {
console.log('Taking a nap...');
await sleep(2000); // Wait for 2 seconds
console.log('Woke up!');
}
demo();
Exemples avancés de pause avec Promise
// Multiple sleep operations in parallel
async function parallelSleep() {
const start = Date.now();
await Promise.all([sleep(1000), sleep(1000)]);
console.log(`Elapsed: ${Date.now() - start}ms`); // ~1000ms
}
// Sequential sleep operations
async function sequentialSleep() {
const start = Date.now();
await sleep(1000);
await sleep(1000);
console.log(`Elapsed: ${Date.now() - start}ms`); // ~2000ms
}
// Sleep with retry logic
async function retryWithSleep(operation, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
if (i === maxRetries - 1) throw error;
console.log(`Retry ${i + 1} after 1 second...`);
await sleep(1000);
}
}
}
Méthode 3 : utiliser le package sleep-promise
Pour ceux qui préfèrent ne pas implémenter leur propre fonction de pause, le package sleep-promise fournit une
solution prête à l’emploi.
// Install: npm install sleep-promise
const sleep = require('sleep-promise');
async function demo() {
console.log('Lights out...');
await sleep(5000); // Wait for 5 seconds
console.log('Good morning, world!');
}
demo();
Avantages : pas besoin d’implémenter votre propre fonction, bien testé
Inconvénients : ajoute une dépendance externe
Méthode 4 : utiliser execSync
Vous pouvez utiliser execSync()
pour exécuter des commandes système de pause. Cette méthode bloque l’ensemble du processus Node.js, donc à
utiliser avec prudence.
const { execSync } = require('child_process');
// Unix/Linux/macOS
function sleep(seconds) {
execSync(`sleep ${seconds}`);
}
// Windows
function sleepWindows(seconds) {
execSync(`timeout /T ${seconds} /NOBREAK`);
}
console.log('Start');
sleep(2); // Blocks for 2 seconds
console.log('End');
Avertissement : cette méthode bloque toute la boucle d’événements et doit être évitée dans les applications de production.
Exemples concrets
Exemple 1 : limitation du débit des API
async function fetchWithRateLimit(urls, delayMs = 1000) {
const results = [];
for (const url of urls) {
try {
const response = await fetch(url);
const data = await response.json();
results.push(data);
// Wait before next request
if (urls.indexOf(url) < urls.length - 1) {
await sleep(delayMs);
}
} catch (error) {
console.error(`Failed to fetch ${url}:`, error);
}
}
return results;
}
// Usage
const urls = ['https://api.example.com/1', 'https://api.example.com/2'];
fetchWithRateLimit(urls, 2000); // 2 second delay between requests
Exemple 2 : polling avec pause
async function pollUntilComplete(taskId, maxAttempts = 10) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const status = await checkTaskStatus(taskId);
if (status === 'completed') {
return await getTaskResult(taskId);
}
if (status === 'failed') {
throw new Error('Task failed');
}
console.log(`Attempt ${attempt}: Task still running, waiting...`);
await sleep(5000); // Wait 5 seconds before next check
}
throw new Error('Task did not complete within time limit');
}
Exemple 3 : indicateur de progression CLI
async function showProgress(message, duration = 3000) {
const dots = ['.', '..', '...'];
let dotIndex = 0;
const interval = setInterval(() => {
process.stdout.write(`\r${message}${dots[dotIndex]} `);
dotIndex = (dotIndex + 1) % dots.length;
}, 500);
await sleep(duration);
clearInterval(interval);
console.log(`\r${message} completed!`);
}
// Usage
await showProgress('Processing data', 5000);
Bonnes pratiques pour la pause dans Node.js
- Utilisez la pause basée sur Promise : privilégiez async/await avec une pause basée sur Promise pour une meilleure lisibilité
- Évitez les pauses bloquantes : n’utilisez jamais
execSync()dans les applications de production - Gérez les erreurs avec soin : entourez toujours les opérations de pause d’un bloc try-catch
- Utilisez des délais adaptés : choisissez des durées de pause raisonnables selon votre cas d’usage
- Envisagez des alternatives : pour des besoins temporels complexes, pensez à des bibliothèques
comme
node-cronoubull
Considérations de performance
Lors de l’implémentation d’une fonctionnalité de pause dans Node.js, tenez compte de ces aspects de performance :
- Le non-bloquant est préférable : la pause basée sur Promise ne bloque pas la boucle d’événements
- Utilisation mémoire : les opérations de pause longues peuvent s’accumuler en mémoire
- Précision : les minuteries JavaScript ne sont pas précises pour des délais très courts
- Nettoyage des ressources : effacez toujours les intervalles et les timeouts lorsqu’ils ne sont plus nécessaires
Conclusion
Implémenter des fonctions d’attente et de pause dans Node.js est essentiel pour de nombreuses applications. Même
si Node.js ne fournit pas de fonction sleep intégrée, l’approche basée sur Promise avec setTimeout() est la méthode
la plus recommandée pour les applications modernes. Elle fournit un code clair et lisible avec la syntaxe
async/await tout en conservant la nature non bloquante de Node.js.
Pour les cas simples, l’approche de base avec setTimeout() fonctionne
bien, tandis que le package sleep-promise offre une
alternative pratique pour ceux qui préfèrent des dépendances externes. Évitez toujours les méthodes bloquantes
comme execSync() dans
les environnements de production.
En suivant les méthodes et les bonnes pratiques présentées dans ce guide, vous pouvez implémenter une fonctionnalité de pause fiable dans Node.js qui améliore les performances et l’expérience utilisateur de votre application. Que vous développiez des API, des outils CLI ou des applications web, comprendre ces patterns de pause vous aidera à créer un code Node.js plus robuste et plus maintenable.