← Назад к вопросам
Приведи пример сложного кода 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.