RequestDeduplicator - sebamar88/bytekit GitHub Wiki
🔗 RequestDeduplicator
EN: Deduplicates in-flight requests so multiple consumers calling the same endpoint at the same time share a single promise instead of firing duplicate network requests.
ES: Deduplica solicitudes en vuelo para que múltiples consumidores que llaman al mismo endpoint al mismo tiempo compartan una sola promesa en vez de disparar solicitudes de red duplicadas.
📦 Import
import { RequestDeduplicator } from "bytekit/request-deduplicator";
// or | o también:
import { RequestDeduplicator } from "bytekit";
⚙️ Constructor
const dedup = new RequestDeduplicator(config?: DeduplicatorConfig);
DeduplicatorConfig
| Property / Propiedad | Type / Tipo | Default | Description (EN) | Descripción (ES) |
|---|---|---|---|---|
keyGenerator |
(url: string, options?: Record<string, unknown>) => string |
(url + sorted options) | Custom function to derive a dedup key | Función personalizada para derivar la clave de deduplicación |
📋 Methods / Métodos
| Method / Método | Signature / Firma | Description (EN) | Descripción (ES) |
|---|---|---|---|
execute |
execute<T>(url: string, fn: () => Promise<T>, options?: Record<string, unknown>): Promise<T> |
Executes fn or returns an existing in-flight promise for the same key |
Ejecuta fn o devuelve una promesa en vuelo existente para la misma clave |
getStats |
getStats(): DeduplicatorStats |
Returns deduplication statistics | Devuelve estadísticas de deduplicación |
getInFlightCount |
getInFlightCount(): number |
Returns the number of currently in-flight requests | Devuelve el número de solicitudes actualmente en vuelo |
clear |
clear(): void |
Clears all in-flight requests and resets stats | Limpia todas las solicitudes en vuelo y reinicia estadísticas |
resetStats |
resetStats(): void |
Resets counters without clearing in-flight requests | Reinicia contadores sin limpiar solicitudes en vuelo |
DeduplicatorStats
interface DeduplicatorStats {
deduplicated: number; // Requests that shared an existing promise / Solicitudes que compartieron una promesa existente
total: number; // Total execute() calls / Llamadas totales a execute()
deduplicationRate: number; // deduplicated / total (0–1) / Tasa de deduplicación (0–1)
}
🧠 How It Works / Cómo Funciona
EN: When
execute()is called, RequestDeduplicator generates a key from the URL (and optional options). If a request with the same key is already in-flight, the same promise is returned to all callers. Once the original promise resolves or rejects, the entry is removed and future calls create a new request.ES: Cuando se llama a
execute(), RequestDeduplicator genera una clave a partir de la URL (y opciones opcionales). Si una solicitud con la misma clave ya está en vuelo, la misma promesa se devuelve a todos los llamadores. Una vez que la promesa original se resuelve o rechaza, la entrada se elimina y futuras llamadas crean una nueva solicitud.
Caller A ──┐
├──▶ execute("/users") ──▶ fetch("/users") ──▶ Response
Caller B ──┘ ↑ │
│ same promise shared │
└─────────────────────────────────────────┘
(Only ONE network request is made / Solo se hace UNA solicitud de red)
💡 Examples / Ejemplos
Basic Usage / Uso Básico
import { RequestDeduplicator } from "bytekit/request-deduplicator";
const dedup = new RequestDeduplicator();
// EN: Even if called 3 times simultaneously, only 1 fetch is made
// ES: Aunque se llame 3 veces simultáneamente, solo se hace 1 fetch
const [r1, r2, r3] = await Promise.all([
dedup.execute("/api/users", () => fetch("/api/users").then(r => r.json())),
dedup.execute("/api/users", () => fetch("/api/users").then(r => r.json())),
dedup.execute("/api/users", () => fetch("/api/users").then(r => r.json())),
]);
// r1 === r2 === r3 (same reference / misma referencia)
In a React Hook / En un Hook de React
const dedup = new RequestDeduplicator();
function useUser(id: string) {
const [user, setUser] = useState(null);
useEffect(() => {
// EN: If multiple components render with the same id,
// only one request is made
// ES: Si múltiples componentes renderizan con el mismo id,
// solo se hace una solicitud
dedup
.execute(`/api/users/${id}`, () =>
fetch(`/api/users/${id}`).then(r => r.json())
)
.then(setUser);
}, [id]);
return user;
}
With Options / Con Opciones
// EN: Different options = different dedup keys
// ES: Diferentes opciones = diferentes claves de deduplicación
await dedup.execute(
"/api/users",
() => fetch("/api/users?role=admin").then(r => r.json()),
{ role: "admin" }
);
await dedup.execute(
"/api/users",
() => fetch("/api/users?role=guest").then(r => r.json()),
{ role: "guest" }
);
// These are separate requests / Estas son solicitudes separadas
Monitoring Stats / Monitorear Estadísticas
const stats = dedup.getStats();
console.log(`Total calls: ${stats.total}`);
console.log(`Deduplicated: ${stats.deduplicated}`);
console.log(`Dedup rate: ${(stats.deduplicationRate * 100).toFixed(1)}%`);
console.log(`In-flight now: ${dedup.getInFlightCount()}`);
Error Handling / Manejo de Errores
// EN: If the original request fails, ALL consumers receive the same error
// ES: Si la solicitud original falla, TODOS los consumidores reciben el mismo error
try {
await dedup.execute("/api/data", async () => {
throw new Error("Network failure");
});
} catch (error) {
console.error(error.message); // "Network failure"
}
// EN: After failure, the in-flight entry is removed,
// so the next call creates a fresh request
// ES: Después del fallo, la entrada en vuelo se elimina,
// por lo que la siguiente llamada crea una solicitud nueva
Custom Key Generator / Generador de Claves Personalizado
const dedup = new RequestDeduplicator({
keyGenerator: (url, options) => {
// EN: Deduplicate based on URL path only (ignore query string)
// ES: Deduplicar basándose solo en la ruta de URL (ignorar query string)
return new URL(url, "http://localhost").pathname;
},
});
⚠️ Important Notes / Notas Importantes
EN: Deduplication only applies to in-flight requests. Once a request completes, the next call to
execute()with the same key will start a new request. If you need caching of completed responses, combine with RequestCache.ES: La deduplicación solo aplica a solicitudes en vuelo. Una vez que una solicitud se completa, la siguiente llamada a
execute()con la misma clave iniciará una nueva solicitud. Si necesitas cachear respuestas completadas, combina con RequestCache.
🔗 See Also / Véase También
- RequestCache — Cache completed responses with TTL / Cachear respuestas completadas con TTL
- RateLimiter — Limit request frequency per URL / Limitar frecuencia de solicitudes por URL
- ApiClient — HTTP client that can integrate deduplication / Cliente HTTP que puede integrar deduplicación