Async Iterator/Generator Pattern
When fetching paginated data from an API, an Async Generator can fetch each page lazily, allowing better control over memory and network usage.
async function* fetchPaginatedData(totalPages) {
for (let page = 1; page <= totalPages; page++) {
await new Promise(resolve => setTimeout(resolve, 1000)); // Simulating delay
yield `Data from page ${page}`;
}
}
(async () => {
for await (const data of fetchPaginatedData(3)) {
console.log(data); // Logs each page's data with a delay
}
})();
Event Loop - Execution Order
The Event Loop in Node.js ensures non-blocking behavior in a single-threaded environment by handling tasks in phases. Understanding the order of execution helps you predict behavior.
console.log("Start");
setImmediate(() => console.log("📢 setImmediate"));
setTimeout(() => console.log("⏳ setTimeout"), 0);
Promise.resolve().then(() => console.log("✅ Promise"));
process.nextTick(() => console.log("⚡ nextTick"));
console.log("End");
Output:
Start
End
⚡ nextTick
✅ Promise
⏳ setTimeout
📢 setImmediate
Phases:
- nextTick: Executes right after the current operation.
-
Promise: Executes after
nextTick
, before timers. - setTimeout: Executes after timers phase.
- setImmediate: Executes in the check phase, after timers.
Semaphore Pattern in Node.js
A Semaphore limits the number of concurrent tasks, useful for controlling access to shared resources. It allows you to limit concurrent execution.
class Semaphore {
constructor(max) {
this.max = max;
this.count = 0;
this.waiting = [];
}
async acquire() {
if (this.count < this.max) {
this.count++;
return;
}
await new Promise(resolve => this.waiting.push(resolve));
}
release() {
this.count--;
const next = this.waiting.shift();
if (next) next();
}
}
const sem = new Semaphore(2);
async function limitedTask(id) {
await sem.acquire();
console.log(`Task ${id} started`);
await new Promise(r => setTimeout(r, 1000)); // Simulate work
sem.release();
}
[1, 2, 3, 4].forEach(limitedTask);
Barrier Pattern in Node.js
The Barrier pattern synchronizes multiple tasks, ensuring they all proceed at the same time once all tasks reach the barrier.
class Barrier {
constructor(count) {
this.count = count;
this.promises = [];
}
async wait() {
const promise = new Promise(resolve => this.promises.push(resolve));
if (--this.count === 0) {
this.promises.forEach(resolve => resolve());
}
return promise;
}
}
const barrier = new Barrier(3);
async function worker() {
console.log('Waiting at barrier');
await barrier.wait();
console.log('Proceeding');
}
worker(); // Task 1
worker(); // Task 2
worker(); // Task 3
AbortController Pattern
The AbortController allows aborting asynchronous tasks. It can be used to cancel long-running operations like fetch requests.
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.catch(error => console.log('Fetch aborted', error));
controller.abort(); // Aborts the fetch
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.