⚡ AutoSnippets PRO EN

JavaScript: Produkcyjne Snippet'y Kodu

Snippet'y Node.js i JavaScript: rate limiting, bezpieczeństwo, obsługa asynchroniczności.

Python JavaScript TypeScript Java C# C++ Go PHP Rust SQL

Na tej stronie:

6. JavaScript: Zaawansowany Rate Limiter

Node.js

Middleware chroniący endpointy przed atakami DDoS i Brute Force.

const rateLimit = require('express-rate-limit');

const apiLimiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 100,
    standardHeaders: true,
    legacyHeaders: false,
    message: { status: 429, error: "Zbyt wiele żądań, spróbuj później." }
});

Kiedy używać

Stosuj na publicznych endpointach API, żeby ograniczyć liczbę żądań z jednego adresu IP w danym oknie czasowym.

Typowe pułapki

Domyślny rate limiter działa w pamięci procesu — przy wielu instancjach serwera każda będzie liczyć limity osobno, potrzebny jest wspólny magazyn (np. Redis).

7. JavaScript: Weryfikacja Podpisu Webhooka

Node.js

Bezpieczna autoryzacja żądań przychodzących za pomocą HMAC SHA256.

const crypto = require('crypto');

function verifyWebhookSignature(req, secretKey) {
    const signature = req.headers['x-hub-signature-256'];
    if (!signature) return false;
    const hmac = crypto.createHmac('sha256', secretKey);
    const digest = `sha256=${hmac.update(req.rawBody).digest('hex')}`;
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}

Kiedy używać

Wymagane przy odbieraniu webhooków od zewnętrznych usług (Stripe, GitHub, Slack), żeby upewnić się, że żądanie faktycznie od nich pochodzi.

Typowe pułapki

Weryfikacja musi działać na surowym (raw) ciele żądania — jeśli framework już sparsował JSON, podpis nie będzie się zgadzał.

8. JavaScript: Kolejka Zadań z Concurrency

JavaScript

Kontrola liczby jednocześnie wykonywanych operacji w tle.

class TaskQueue {
    constructor(concurrency = 2) {
        this.concurrency = concurrency;
        this.running = 0;
        this.queue = [];
    }
    add(task) {
        return new Promise((resolve, reject) => {
            this.queue.push({ task, resolve, reject });
            this.next();
        });
    }
    next() {
        if (this.running >= this.concurrency || this.queue.length === 0) return;
        this.running++;
        const { task, resolve, reject } = this.queue.shift();
        task().then(resolve).catch(reject).finally(() => { this.running--; this.next(); });
    }
}

Kiedy używać

Przydatne, gdy musisz przetworzyć dużo zadań asynchronicznych, ale nie możesz odpalić ich wszystkich naraz (np. limity API).

Typowe pułapki

Brak obsługi błędów pojedynczego zadania może zablokować całą kolejkę — upewnij się, że odrzucona (rejected) promisa nie zatrzymuje kolejnych zadań.

9. JavaScript: Bezpieczne Haszowanie Haseł

Node.js

Generowanie solonych skrótów i weryfikacja z użyciem bcrypt.

const bcrypt = require('bcrypt');

async function hashPassword(plainPassword) {
    return await bcrypt.hash(plainPassword, 10);
}

async function verifyPassword(plainPassword, hashed) {
    return await bcrypt.compare(plainPassword, hashed);
}

Kiedy używać

Podstawa każdego systemu logowania — nigdy nie przechowuj haseł jawnym tekstem ani nawet zwykłym hashem MD5/SHA1.

Typowe pułapki

Zbyt niski cost factor (liczba rund) w bcrypt sprawia, że hash jest szybki do złamania — 10-12 to bezpieczne minimum w 2026.

10. JavaScript: Robust Fetch z Timeoutem

JavaScript

Klient HTTP odporny na zwieszające się mikroserwisy (AbortController).

async function robustFetch(url, options = {}, timeoutMs = 5000) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), timeoutMs);
    try {
        const res = await fetch(url, { ...options, signal: controller.signal });
        clearTimeout(timer);
        if (!res.ok) throw new Error(`HTTP error: ${res.status}`);
        return await res.json();
    } catch (err) {
        clearTimeout(timer);
        throw err;
    }
}

Kiedy używać

Przydatne wszędzie, gdzie wywołujesz zewnętrzne API i chcesz uniknąć wiszącego żądania blokującego resztę aplikacji.

Typowe pułapki

Sam timeout nie obsługuje ponawiania (retry) — przy niestabilnych połączeniach warto połączyć go z logiką retry z backoffem.

59. JavaScript: Debounce i Throttle

JavaScript

Dwie techniki ograniczania częstotliwości wywołań funkcji, np. przy scrollu czy wpisywaniu tekstu.

function debounce(func, delay) {
    let timer;
    return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => func.apply(this, args), delay);
    };
}

function throttle(func, limit) {
    let inThrottle;
    return function (...args) {
        if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            setTimeout(() => (inThrottle = false), limit);
        }
    };
}

const searchHandler = debounce((query) => console.log("Szukam:", query), 300);

Kiedy używać

Debounce stosuj przy polu wyszukiwania (czekasz aż user skończy pisać), throttle przy scrollu czy resize (ograniczasz częstotliwość, ale nie czekasz na 'koniec' zdarzenia).

Typowe pułapki

Mylenie debounce z throttle to częsty błąd — debounce może nigdy się nie wykonać przy ciągłej aktywności, throttle gwarantuje wykonanie co określony interwał.

60. JavaScript: Własny EventEmitter

JavaScript

Prosta implementacja wzorca publish-subscribe bez zewnętrznych bibliotek.

class EventEmitter {
    constructor() {
        this.events = {};
    }
    on(event, listener) {
        (this.events[event] ??= []).push(listener);
        return this;
    }
    emit(event, ...args) {
        (this.events[event] || []).forEach(listener => listener(...args));
    }
    off(event, listener) {
        this.events[event] = (this.events[event] || []).filter(l => l !== listener);
    }
}

const emitter = new EventEmitter();
emitter.on("userCreated", (user) => console.log("Nowy użytkownik:", user.name));

Kiedy używać

Przydatne do komunikacji między niezależnymi modułami aplikacji bez bezpośredniego importowania się nawzajem.

Typowe pułapki

Brak metody off() (odsubskrybowania) prowadzi do wycieków pamięci w długożyjących aplikacjach — zawsze usuwaj listenery, których już nie potrzebujesz.

61. JavaScript: LRU Cache (Map-based)

JavaScript

Cache o ograniczonym rozmiarze, usuwający najdawniej używane elementy.

class LRUCache {
    constructor(capacity) {
        this.capacity = capacity;
        this.cache = new Map();
    }
    get(key) {
        if (!this.cache.has(key)) return undefined;
        const value = this.cache.get(key);
        this.cache.delete(key);
        this.cache.set(key, value);
        return value;
    }
    put(key, value) {
        if (this.cache.has(key)) this.cache.delete(key);
        else if (this.cache.size >= this.capacity) {
            this.cache.delete(this.cache.keys().next().value);
        }
        this.cache.set(key, value);
    }
}

Kiedy używać

Stosuj przy cachowaniu wyników kosztownych operacji w pamięci, gdy chcesz ograniczyć zużycie RAM do stałego rozmiaru.

Typowe pułapki

Map w JavaScript zachowuje kolejność wstawiania, co ta implementacja wykorzystuje — użycie zwykłego obiektu ({}) zamiast Map nie dałoby tej samej gwarancji kolejności.

62. JavaScript: WebSocket z Auto-Reconnect

JavaScript

Klient WebSocket automatycznie ponawiający połączenie po jego zerwaniu.

function createResilientSocket(url, onMessage) {
    let socket;
    let reconnectDelay = 1000;

    function connect() {
        socket = new WebSocket(url);
        socket.onmessage = onMessage;
        socket.onopen = () => { reconnectDelay = 1000; };
        socket.onclose = () => {
            setTimeout(connect, reconnectDelay);
            reconnectDelay = Math.min(reconnectDelay * 2, 30000);
        };
    }

    connect();
    return { close: () => socket.close() };
}

Kiedy używać

Niezbędne w aplikacjach czasu rzeczywistego (czaty, notyfikacje na żywo), gdzie chwilowa utrata połączenia nie powinna wymagać ręcznego odświeżenia strony.

Typowe pułapki

Brak górnego limitu na reconnectDelay (exponential backoff) mógłby przy długiej awarii próbować łączyć się co kilka minut zamiast max 30 sekund — jak w tym przykładzie.

63. JavaScript: Prosty Pub/Sub w Pamięci

JavaScript

Lekki mechanizm publikuj-subskrybuj do komunikacji między komponentami frontendu.

const PubSub = {
    topics: {},
    subscribe(topic, callback) {
        (this.topics[topic] ??= []).push(callback);
        return () => this.unsubscribe(topic, callback);
    },
    unsubscribe(topic, callback) {
        this.topics[topic] = (this.topics[topic] || []).filter(cb => cb !== callback);
    },
    publish(topic, data) {
        (this.topics[topic] || []).forEach(cb => cb(data));
    }
};

const unsubscribe = PubSub.subscribe("cartUpdated", (cart) => console.log(cart));

Kiedy używać

Przydatne w komponentowych aplikacjach frontendowych, gdzie dwa niezwiązane ze sobą komponenty muszą reagować na te same zdarzenia bez wspólnego rodzica.

Typowe pułapki

Subskrypcja zwracająca funkcję unsubscribe (jak w przykładzie) jest łatwa do pominięcia — brak wywołania jej przy odmontowaniu komponentu to częsta przyczyna wycieków pamięci w SPA.

64. JavaScript: Deep Clone i Deep Merge

JavaScript

Głębokie kopiowanie i scalanie zagnieżdżonych obiektów bez mutowania oryginałów.

function deepClone(obj) {
    if (obj === null || typeof obj !== "object") return obj;
    if (Array.isArray(obj)) return obj.map(deepClone);
    return Object.fromEntries(
        Object.entries(obj).map(([k, v]) => [k, deepClone(v)])
    );
}

function deepMerge(target, source) {
    const result = deepClone(target);
    for (const key in source) {
        if (source[key] instanceof Object && key in result) {
            result[key] = deepMerge(result[key], source[key]);
        } else {
            result[key] = source[key];
        }
    }
    return result;
}

Kiedy używać

Stosuj przy scalaniu konfiguracji (np. domyślne ustawienia + nadpisania użytkownika) albo aktualizacji stanu bez mutowania oryginalnych obiektów.

Typowe pułapki

structuredClone() dostępne natywnie w nowoczesnych przeglądarkach robi to samo szybciej i bezpieczniej niż ręczna implementacja — użyj go, jeśli nie potrzebujesz wsparcia starszych środowisk.

65. JavaScript: In-Memory Rate Limiter (Token Bucket)

JavaScript

Implementacja limitera żądań bez zewnętrznych zależności jak Redis.

class TokenBucket {
    constructor(capacity, refillRate) {
        this.capacity = capacity;
        this.tokens = capacity;
        this.refillRate = refillRate;
        this.lastRefill = Date.now();
    }
    allow() {
        const now = Date.now();
        const elapsed = (now - this.lastRefill) / 1000;
        this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
        this.lastRefill = now;
        if (this.tokens >= 1) {
            this.tokens -= 1;
            return true;
        }
        return false;
    }
}

const limiter = new TokenBucket(10, 2);
if (!limiter.allow()) console.log("Limit przekroczony");

Kiedy używać

Przydatne do prostych, jednoprocesowych aplikacji Node.js, gdzie nie chcesz dodawać zależności od Redisa tylko po to, żeby ograniczyć liczbę żądań.

Typowe pułapki

Ten limiter trzyma stan w pamięci pojedynczego procesu — przy wielu instancjach aplikacji (load balancing) każda liczy limity osobno, co efektywnie zwielokrotnia dozwolony limit.