← Назад к вопросам

Приведи пример сложного кода JavaScript

1.0 Junior🔥 182 комментариев
#Автоматизация тестирования

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сложный код на JavaScript: Реализация паттерна "Наблюдатель" с асинхронной обработкой и мемоизацией

Вот пример сложного кода на JavaScript, который демонстрирует несколько продвинутых концепций в одном модуле. Этот код реализует паттерн "Наблюдатель" (Observer) с поддержкой асинхронных операций, мемоизации результатов и обработкой ошибок с откатом состояния.

/**
 * Сложная реализация асинхронного EventEmitter с мемоизацией и обработкой ошибок
 */
class AdvancedEventEmitter {
  constructor() {
    this._events = new Map();
    this._memory = new Map();
    this._pendingOperations = new WeakMap();
    this._middlewareChain = [];
  }

  /**
   * Регистрация обработчика события с поддержкой мемоизации
   * @param {string} event - Название события
   * @param {Function} handler - Асинхронный обработчик
   * @param {Object} options - Опции: memoize, priority, timeout
   */
  on(event, handler, options = {}) {
    if (!this._events.has(event)) {
      this._events.set(event, []);
    }

    const wrapper = async (...args) => {
      const cacheKey = options.memoize ? 
        `${event}:${JSON.stringify(args)}` : null;

      // Проверка кеша для мемоизации
      if (cacheKey && this._memory.has(cacheKey)) {
        console.log(`Возвращаю закешированный результат для ${cacheKey}`);
        return this._memory.get(cacheKey);
      }

      // Таймаут для асинхронной операции
      const timeoutPromise = options.timeout ? 
        new Promise((_, reject) => 
          setTimeout(() => reject(new Error('Timeout')), options.timeout)
        ) : null;

      try {
        // Запуск с таймаутом или без
        const result = options.timeout ? 
          await Promise.race([handler(...args), timeoutPromise]) :
          await handler(...args);

        // Кеширование результата
        if (cacheKey && options.memoize) {
          this._memory.set(cacheKey, result);
        }

        return result;
      } catch (error) {
        // Кастомная обработка ошибок
        this._handleError(event, error, args);
        throw error;
      }
    };

    wrapper.priority = options.priority || 0;
    wrapper.originalHandler = handler;

    this._events.get(event).push(wrapper);
    this._events.get(event).sort((a, b) => b.priority - a.priority);
  }

  /**
   * Асинхронный вызов события с поддержкой middleware
   * @param {string} event - Название события
   * @param {...any} args - Аргументы
   * @returns {Promise<Array>} - Результаты всех обработчиков
   */
  async emit(event, ...args) {
    if (!this._events.has(event)) {
      return [];
    }

    const handlers = this._events.get(event);
    const results = [];
    const rollbackStack = [];

    // Применение middleware
    const processedArgs = await this._applyMiddleware(event, args);

    for (const handler of handlers) {
      try {
        // Использование Proxy для отслеживания изменений
        const stateTracker = this._createStateTracker();
        
        const result = await handler(...processedArgs);
        
        // Сохранение состояния для возможного отката
        if (stateTracker.hasChanges()) {
          rollbackStack.push(stateTracker.getSnapshot());
        }
        
        results.push(result);
        
      } catch (error) {
        // Выполнение отката при ошибке
        await this._executeRollback(rollbackStack);
        throw error;
      }
    }

    // Оптимизация: очистка старых кешей
    this._cleanupMemory();
    
    return results;
  }

  /**
   * Приватный метод для применения middleware
   */
  async _applyMiddleware(event, args) {
    let processedArgs = args;
    
    for (const middleware of this._middlewareChain) {
      if (typeof middleware === 'function') {
        processedArgs = await middleware(event, processedArgs);
      }
    }
    
    return processedArgs;
  }

  /**
   * Создание трекера состояния с использованием Proxy
   */
  _createStateTracker() {
    const changes = new Set();
    const snapshot = new Map();
    
    const handler = {
      set(target, property, value) {
        if (!changes.has(property)) {
          snapshot.set(property, target[property]);
          changes.add(property);
        }
        target[property] = value;
        return true;
      }
    };
    
    return {
      hasChanges: () => changes.size > 0,
      getSnapshot: () => new Map(snapshot),
      proxy: (obj) => new Proxy(obj, handler)
    };
  }

  /**
   * Выполнение отката изменений
   */
  async _executeRollback(rollbackStack) {
    for (const snapshot of rollbackStack.reverse()) {
      for (const [property, value] of snapshot) {
        // Восстановление предыдущего состояния
        // (в реальном коде здесь была бы сложная логика)
        console.log(`Откат: ${property} = ${value}`);
      }
    }
  }

  /**
   * Очистка устаревших кешированных данных
   */
  _cleanupMemory() {
    const maxEntries = 100;
    if (this._memory.size > maxEntries) {
      const entries = Array.from(this._memory.entries());
      entries.slice(0, entries.length - maxEntries)
        .forEach(([key]) => this._memory.delete(key));
    }
  }

  /**
   * Кастомная обработка ошибок
   */
  _handleError(event, error, args) {
    // Сложная логика обработки ошибок
    const errorContext = {
      timestamp: new Date().toISOString(),
      event,
      args: args.map(arg => 
        typeof arg === 'object' ? JSON.stringify(arg).slice(0, 100) : String(arg)
      ),
      error: error.message
    };
    
    console.error('Контекст ошибки:', errorContext);
    
    // Дополнительная логика (отправка в мониторинг и т.д.)
    if (error.name === 'TypeError') {
      console.warn('Обнаружена ошибка типа, проверьте входные данные');
    }
  }
}

/**
 * Пример использования сложной системы событий
 */
async function demonstrateComplexCode() {
  const emitter = new AdvancedEventEmitter();
  
  // Регистрация обработчиков с разными опциями
  emitter.on('data.process', async (data) => {
    console.log('Обработка данных (высокий приоритет):', data.id);
    await new Promise(resolve => setTimeout(resolve, 100));
    return { ...data, processed: true };
  }, { priority: 10, memoize: true });
  
  emitter.on('data.process', async (data) => {
    console.log('Валидация данных (низкий приоритет):', data.id);
    if (!data.id) throw new Error('Invalid data');
    return { ...data, validated: true };
  }, { priority: 1, timeout: 500 });
  
  try {
    // Асинхронный вызов
    const results = await emitter.emit('data.process', { id: 'test-123', value: 42 });
    console.log('Результаты:', results);
    
    // Повторный вызов - данные будут взяты из кеша
    const cachedResults = await emitter.emit('data.process', { id: 'test-123', value: 42 });
    console.log('Закешированные результаты:', cachedResults);
    
  } catch (error) {
    console.error('Критическая ошибка:', error);
  }
}

// Запуск демонстрации
demonstrateComplexCode().catch(console.error);

Почему этот код считается сложным?

1. Многопоточные концепции в однопоточном JavaScript

  • Использование Promise.race() для реализации таймаутов
  • Асинхронные цепочки с обработкой ошибок
  • Управление состоянием в асинхронном контексте

2. Сложные паттерны проектирования

  • Реализация паттерна Наблюдатель с расширенной функциональностью
  • Прокси (Proxy) для отслеживания изменений состояния
  • Middlewares для обработки аргументов

3. Продвинутые оптимизации

  • Мемоизация результатов с сериализацией аргументов
  • Управление памятью с автоматической очисткой кеша
  • Приоритизация обработчиков событий

4. Надежная обработка ошибок

  • Кастомная система отката (rollback) изменений
  • Контекстное логирование ошибок
  • Разделение ошибок по типам

5. Слабые ссылки и управление памятью

  • Использование WeakMap для хранения временных данных
  • Автоматическая очистка устаревших записей

Этот код демонстрирует, как современный JavaScript может быть использован для создания сложных, производственных систем с поддержкой асинхронности, отказоустойчивости и оптимизаций производительности. Такая реализация требует глубокого понимания event loop, promises, паттернов проектирования и управления памятью в JavaScript.