forked from CITKParus/P8-ExchangeService
ЦИТК-795: CodeReview - deepMerge в стрелочном стиле, дополнительные комментарии по коду
This commit is contained in:
parent
72feca2a38
commit
b2b7d01342
@ -30,8 +30,9 @@ const { SPROTOCOL_HTTP, SPROTOCOL_KAFKA } = require("../models/obj_service"); //
|
|||||||
|
|
||||||
//Глубокое клонирование
|
//Глубокое клонирование
|
||||||
const deepClone = value => {
|
const deepClone = value => {
|
||||||
//Клонируем объект в зависимости от его типа, сохраняя прототипы
|
//Буфер для фиксации "клонированных" элементов исходного объекта
|
||||||
const seen = new WeakMap();
|
const seen = new WeakMap();
|
||||||
|
//Функция рекурсивного клонирования (разбирает тип полученного значения и в зависимости от него выполняет клонирование, сохраняя прототипы)
|
||||||
const clone = val => {
|
const clone = val => {
|
||||||
//Примитивы и функции возвращаем как есть
|
//Примитивы и функции возвращаем как есть
|
||||||
if (val === null || typeof val !== "object") return val;
|
if (val === null || typeof val !== "object") return val;
|
||||||
@ -104,10 +105,12 @@ const deepClone = value => {
|
|||||||
});
|
});
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
//Выполняем копирование рекурсивно с верхнего уровня
|
||||||
try {
|
try {
|
||||||
|
//Возвращаем что получилось
|
||||||
return clone(value);
|
return clone(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//В случае непредвиденной ошибки формируем информативное исключение
|
//В случае непредвиденной ошибки формируем исключение
|
||||||
const err = new Error("Ошибка глубокого копирования объекта");
|
const err = new Error("Ошибка глубокого копирования объекта");
|
||||||
err.originalError = e;
|
err.originalError = e;
|
||||||
throw err;
|
throw err;
|
||||||
@ -407,30 +410,33 @@ const getNowString = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Глубокое слияние объектов
|
//Глубокое слияние объектов
|
||||||
function deepMerge(...sources) {
|
const deepMerge = (...sources) => {
|
||||||
|
//Проверка на простой объект (не имеет специального поведения или прототипа)
|
||||||
const isPlainObject = value => Object.prototype.toString.call(value) === "[object Object]";
|
const isPlainObject = value => Object.prototype.toString.call(value) === "[object Object]";
|
||||||
|
//Клоникарование значения
|
||||||
const cloneValue = value => {
|
const cloneValue = value => deepClone(value);
|
||||||
return deepClone(value);
|
//Буфер для результата
|
||||||
};
|
|
||||||
|
|
||||||
const target = {};
|
const target = {};
|
||||||
|
//Обходим входные параметры по очереди
|
||||||
for (const source of sources) {
|
for (const source of sources) {
|
||||||
|
//Пропускаем непростые объекты - сливать можем только простые
|
||||||
if (!isPlainObject(source)) continue;
|
if (!isPlainObject(source)) continue;
|
||||||
|
//Обходим пары "ключ-значение"
|
||||||
for (const [key, value] of Object.entries(source)) {
|
for (const [key, value] of Object.entries(source)) {
|
||||||
|
//Если значение ключа - объект
|
||||||
if (isPlainObject(value)) {
|
if (isPlainObject(value)) {
|
||||||
|
//Сливаем рекурсивно
|
||||||
if (!isPlainObject(target[key])) target[key] = {};
|
if (!isPlainObject(target[key])) target[key] = {};
|
||||||
target[key] = deepMerge(target[key], value);
|
target[key] = deepMerge(target[key], value);
|
||||||
} else {
|
} else {
|
||||||
|
//Примитивы - просто клонируем
|
||||||
target[key] = cloneValue(value);
|
target[key] = cloneValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Возвращаем собранный буфер, содержащий все слитые воедино объекты-параметры
|
||||||
return target;
|
return target;
|
||||||
}
|
};
|
||||||
|
|
||||||
//Глубокое копирование объекта
|
//Глубокое копирование объекта
|
||||||
const deepCopyObject = obj => JSON.parse(JSON.stringify(obj));
|
const deepCopyObject = obj => JSON.parse(JSON.stringify(obj));
|
||||||
@ -509,27 +515,31 @@ const getURLProtocol = sURL => {
|
|||||||
|
|
||||||
//Обёртывание промиса в таймаут исполнения
|
//Обёртывание промиса в таймаут исполнения
|
||||||
const wrapPromiseTimeout = (timeout, executor) => {
|
const wrapPromiseTimeout = (timeout, executor) => {
|
||||||
|
//Проверяем входные параметры - должен быть указан ненулевой таймаут и функция-исполнитель промиса
|
||||||
if (!timeout || typeof executor !== "function") {
|
if (!timeout || typeof executor !== "function") {
|
||||||
|
//Разрешаем сразу, не ожидая
|
||||||
return executor ? executor() : Promise.resolve();
|
return executor ? executor() : Promise.resolve();
|
||||||
}
|
}
|
||||||
|
//Параметры прошли проверку, создаем экхемпляр контроллера прерывания асинхронного процесса
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
//Подготовим объект для выбрасывания ошибки
|
||||||
const sMessage = `Истёк интервал ожидания (${timeout} мс) завершения асинхронного процесса.`;
|
const sMessage = `Истёк интервал ожидания (${timeout} мс) завершения асинхронного процесса.`;
|
||||||
const timeoutError = new Error(sMessage);
|
const timeoutError = new Error(sMessage);
|
||||||
timeoutError.error = sMessage;
|
timeoutError.error = sMessage;
|
||||||
|
//Буфер для идентификатора таймера
|
||||||
let timeoutPid;
|
let timeoutPid;
|
||||||
|
//Создаём промис с взведенным таумером на у казанный таймаут, промис будет "отклонён" по истечении таймера, но перед этим контроллер прерывания выдаст "сигнал" на отмену осинхронного процесса
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
const timeoutPromise = new Promise((_, reject) => {
|
||||||
timeoutPid = setTimeout(() => {
|
timeoutPid = setTimeout(() => {
|
||||||
controller.abort(timeoutError);
|
controller.abort(timeoutError);
|
||||||
reject(timeoutError);
|
reject(timeoutError);
|
||||||
}, timeout);
|
}, timeout);
|
||||||
});
|
});
|
||||||
|
//Создаём промис с функцией-исполнителем асинхронного процесса
|
||||||
const taskPromise = Promise.resolve(executor(controller.signal));
|
const taskPromise = Promise.resolve(executor(controller.signal));
|
||||||
|
//Запускаем оба промиса в режиме "гонка" - кто "быстрее" исполнится
|
||||||
return Promise.race([taskPromise, timeoutPromise]).finally(() => {
|
return Promise.race([taskPromise, timeoutPromise]).finally(() => {
|
||||||
|
//В любом случае не забываем зачистить взведённый таймер
|
||||||
if (timeoutPid) clearTimeout(timeoutPid);
|
if (timeoutPid) clearTimeout(timeoutPid);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user