Разбираем Proxy API, с помощью которого можно перехватывать и переопределять базовые операции с объектами и функциями: контролировать доступ и изменение данных, управлять видимостью и перечислением свойств, отслеживать вызовы функций и создание экземпляров. Используется для валидации, логирования, метапрограммирования и создания гибкого поведения объектов.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥9🤝4❤2
Создаём индекс данных из массива для быстрого поиска через Map!
При работе с данными из API часто требуется получать элементы массива по идентификатору. Самый простой вариант — использовать
Например, поиск пользователя по
Метод
Для единичного поиска этого достаточно. Но если выполнять такие операции внутри циклов или часто обращаться к одним и тем же данным, появляется лишняя нагрузка: каждый вызов снова проходит массив от начала до нужного элемента.
Вместо этого можно заранее создать индекс, где идентификатор будет использоваться как ключ, а объект — как значение:
Теперь получение пользователя выполняется через ключ без повторного перебора массива.
По сложности подходы отличаются:
Поэтому такой паттерн особенно полезен при работе с большими коллекциями и частыми операциями чтения.
Например, пользователи и их настройки могут приходить отдельными запросами:
После создания индекса можно собрать итоговую структуру данных без вложенных поисков внутри массива:
В результате каждый объект получает связанные данные через быстрый поиск по ключу. Такой подход часто применяется при подготовке данных для таблиц, списков, кэширования результатов запросов, нормализации состояния приложения и работе с большими наборами данных.
Для создания индекса также можно использовать обычный объект:
Однако
Важно учитывать, что индекс — это дополнительная структура в памяти. Если нужен один поиск, обычный
🔥 Создание индекса из массива позволяет заранее подготовить данные для быстрого доступа и избежать повторных линейных поисков при обработке коллекций.
📣 JS Ready | #практика
При работе с данными из API часто требуется получать элементы массива по идентификатору. Самый простой вариант — использовать
find(), но при большом количестве повторных поисков такой подход приводит к постоянному перебору коллекции.Например, поиск пользователя по
id:const users = [
{
id: 1,
name: "Alex"
},
{
id: 2,
name: "John"
}
];
const user = users.find(
user => user.id === 2
);
console.log(user);
Метод
find() последовательно проверяет элементы массива и возвращает первое совпадение.Для единичного поиска этого достаточно. Но если выполнять такие операции внутри циклов или часто обращаться к одним и тем же данным, появляется лишняя нагрузка: каждый вызов снова проходит массив от начала до нужного элемента.
Вместо этого можно заранее создать индекс, где идентификатор будет использоваться как ключ, а объект — как значение:
const usersById = new Map(
users.map(user => [
user.id,
user
])
);
console.log(
usersById.get(2)
);
Теперь получение пользователя выполняется через ключ без повторного перебора массива.
По сложности подходы отличаются:
find() - O(n)
Map.get() - O(1) в среднем
Поэтому такой паттерн особенно полезен при работе с большими коллекциями и частыми операциями чтения.
Например, пользователи и их настройки могут приходить отдельными запросами:
const settings = [
{
userId: 1,
theme: "dark"
},
{
userId: 2,
theme: "light"
}
];
const settingsByUser = new Map(
settings.map(item => [
item.userId,
item
])
);
После создания индекса можно собрать итоговую структуру данных без вложенных поисков внутри массива:
const result = users.map(user => ({
...user,
settings: settingsByUser.get(user.id)
}));
console.log(result);В результате каждый объект получает связанные данные через быстрый поиск по ключу. Такой подход часто применяется при подготовке данных для таблиц, списков, кэширования результатов запросов, нормализации состояния приложения и работе с большими наборами данных.
Для создания индекса также можно использовать обычный объект:
const usersById = Object.fromEntries(
users.map(user => [
user.id,
user
])
);
console.log(usersById[2]);
Однако
Map лучше подходит для динамических коллекций, где требуется часто добавлять, удалять или получать элементы. Кроме того, он поддерживает любые типы ключей, имеет встроенное свойство size и не зависит от прототипа объекта.Важно учитывать, что индекс — это дополнительная структура в памяти. Если нужен один поиск, обычный
find() может быть проще и понятнее. Но при многократном доступе к данным создание индекса позволяет значительно сократить количество лишних операций.Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍6🔥5
Например, Smoke Testing проверяет, что критичные эндпоинты вообще доступны, а Contract Testing помогает убедиться, что запросы и ответы по-прежнему соответствуют API-контракту.
На картинке — 9 основных видов API-тестирования: от функциональных и интеграционных тестов до нагрузочного, security- и fuzz-тестирования.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍7🤝3❤1
JavaScript умеет освобождать ресурсы сам, без finally!
Когда код временно открывает ресурс, соединение, файл,
Современный JS поддерживает явное управление ресурсами. Объект может определить
После этого управление жизненным циклом ресурса становится некой частью языка:
Для ресурсов с асинхронной очисткой существует отдельная пара
🔥
📣 JS Ready | #совет
Когда код временно открывает ресурс, соединение, файл,
lock или подписку — его обязательно нужно закрыть даже при ошибке. Обычно для этого пишут try/finally:const connection = openConnection();
try {
await connection.query(sql);
} finally {
connection.close();
}
Современный JS поддерживает явное управление ресурсами. Объект может определить
Symbol.dispose, а using гарантированно вызовет его при выходе из области видимости:function openConnection() {
return {
query(sql) {
return db.query(sql);
},
[Symbol.dispose]() {
db.close();
}
};
}После этого управление жизненным циклом ресурса становится некой частью языка:
{
using connection = openConnection();
await connection.query(sql);
}
// connection[Symbol.dispose]() уже вызванДля ресурсов с асинхронной очисткой существует отдельная пара
await using и Symbol.asyncDispose:await using connection = await connect();
await connection.query(sql);
// await connection[Symbol.asyncDispose]()
using полезен для ресурсов с чётким временем жизни: файлов, соединений, блокировок и временных подписок. Жизненным циклом управляет сам scope.Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥5🤝4
Например, балансировщик нагрузки распределяет входящий трафик между серверами, кэширование снижает нагрузку на базу данных, а очереди сообщений позволяют сервисам работать асинхронно и меньше зависеть друг от друга.
На картинке — 12 архитектурных концепций, которые полезно знать разработчику: от CDN и API Gateway до шардинга, consistent hashing и автомасштабирования.
Сохрани, чтобы была под рукой!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🤝8❤5
Одинаковый синтаксис
..., но разные задачи: Spread раскрывает элементы и свойства, а Rest собирает оставшиеся значения в массив или объект.На картинке — различия, синтаксис и примеры использования Spread и Rest при работе с массивами, объектами и функциями.
Сохрани как краткую памятку!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥9🤝4❤1
Array.prototype.fill() — заполнение массивов и особенности работы со ссылками!
Метод принимает три аргумента:
Один из распространённых вариантов использования — создание массивов состояний:
Такой подход используется в алгоритмах с индексами, графах, таблицах состояний и буферных структурах.
Главная особенность
Результат:
Все элементы ссылаются на один объект. Для создания независимых значений необходимо генерировать объект для каждой позиции:
Также
Метод поддерживает отрицательные индексы:
📣 JS Ready | #практика
Array.prototype.fill() — часто используемый метод, который заменяет элементы массива указанным значением. Он изменяет исходный массив и применяется при подготовке структур данных, создании массивов фиксированной длины и инициализации состояний. Пример:const numbers = new Array(5).fill(0);
console.log(numbers);
// [0, 0, 0, 0, 0]
Метод принимает три аргумента:
array.fill(value, start, end);
value — значение для заполнения, start — индекс начала изменения, end — граница диапазона без включения самого индекса. Например:const values = [10, 20, 30, 40, 50];
values.fill(1, 2, 4);
console.log(values);
// [10, 20, 1, 1, 50]
Один из распространённых вариантов использования — создание массивов состояний:
const visited = new Array(100).fill(false);
visited[25] = true;
Такой подход используется в алгоритмах с индексами, графах, таблицах состояний и буферных структурах.
Главная особенность
fill() проявляется при работе с объектами. Метод не создаёт отдельные экземпляры, а записывает одно и то же значение во все позиции массива:const items = new Array(3).fill({
active: false
});
items[0].active = true;
console.log(items);Результат:
[
{ active: true },
{ active: true },
{ active: true }
]
Все элементы ссылаются на один объект. Для создания независимых значений необходимо генерировать объект для каждой позиции:
const items = Array.from(
{ length: 3 },
() => ({
active: false
})
);
Также
fill() изменяет разреженные массивы, создавая реальные индексные свойства:const array = new Array(3);
console.log(Object.keys(array));
// []
array.fill(null);
console.log(Object.keys(array));
// ["0", "1", "2"]
Метод поддерживает отрицательные индексы:
const numbers = [1, 2, 3, 4, 5];
numbers.fill(0, -2);
console.log(numbers);
// [1, 2, 3, 0, 0]
Array.prototype.fill() не выполняет копирование значений. Для примитивов поведение обычно ожидаемое, но при работе с объектами и массивами необходимо учитывать ссылочную модель JavaScript. Метод, который хорошо показывает важный принцип языка: в JavaScript значение и ссылка на объект — это разные вещи.Please open Telegram to view this post
VIEW IN TELEGRAM
🤝8❤6👍4
Event Sourcing меняет привычный подход к хранению данных: вместо перезаписи текущего состояния система сохраняет последовательность событий, из которых это состояние можно восстановить.В этом посте:
• Разберём, почему в Event Sourcing состояние становится производным;
• Отделим команды от событий и поймём их разные роли;
• Реализуем восстановление состояния через последовательный replay событий;
• Разберём, почему события становятся источником истины, а не просто журналом изменений.
Такой подход сохраняет не только результат изменений, но и их причинную историю, позволяя строить новые представления данных и воспроизводить состояние системы на основе событий.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍6❤3
Получаем только изменённые поля объекта!
При изменении состояния приложения можно сравнить предыдущую и текущую версию объекта, чтобы определить только обновлённые значения. Такой
Для получения изменённых полей можно преобразовать объект в массив пар через
В результате получится объект, содержащий только изменённые поля:
Такой подход применяется при обновлении состояния во frontend-приложениях, работе с формами и подготовке частичных изменений для API через
Вместо отправки всей структуры можно передать только те значения, которые действительно были изменены.
Проверка через количество ключей позволяет определить, были ли изменения вообще. Если объект
Важно учитывать, что данный способ выполняет только поверхностное сравнение (
Вложенные объекты сравниваются по ссылке, поэтому одинаковая структура внутри разных объектов не делает их равными. Для таких случаев требуется использовать глубокое сравнение (
🔥 Также при реализации реальных обновлений через
📣 JS Ready | #практика
При изменении состояния приложения можно сравнить предыдущую и текущую версию объекта, чтобы определить только обновлённые значения. Такой
diff позволяет отделить изменившиеся поля от тех, которые остались без изменений, и использовать только актуальные данные для дальнейшей обработки.const oldUser = {
name: "Alex",
age: 30,
role: "developer"
};
const newUser = {
name: "Alex",
age: 31,
role: "developer"
};Для получения изменённых полей можно преобразовать объект в массив пар через
Object.entries(), отфильтровать только отличающиеся значения и собрать новый объект обратно с помощью Object.fromEntries().const changes = Object.fromEntries(
Object.entries(newUser)
.filter(([key, value]) =>
!Object.is(value, oldUser[key])
)
);
console.log(changes);
В результате получится объект, содержащий только изменённые поля:
{
age: 31
}Такой подход применяется при обновлении состояния во frontend-приложениях, работе с формами и подготовке частичных изменений для API через
PATCH запросы. Вместо отправки всей структуры можно передать только те значения, которые действительно были изменены.
const hasChanges =
Object.keys(changes).length > 0;
console.log(hasChanges);
Проверка через количество ключей позволяет определить, были ли изменения вообще. Если объект
changes пустой, значит исходное и новое состояние полностью совпадают.Важно учитывать, что данный способ выполняет только поверхностное сравнение (
shallow diff) и проверяет значения первого уровня объекта.const first = {
profile: {
name: "Alex"
}
};
const second = {
profile: {
name: "Alex"
}
};
console.log(first.profile === second.profile);
// falseВложенные объекты сравниваются по ссылке, поэтому одинаковая структура внутри разных объектов не делает их равными. Для таких случаев требуется использовать глубокое сравнение (
deep comparison) или отдельную логику построения diff.PATCH нужно отдельно учитывать удаление полей, так как простой shallow diff определяет только добавленные и изменённые значения.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤7👍4🤝1
Например,
await приостанавливает выполнение текущей async-функции до завершения Promise, а try...catch позволяет удобно обрабатывать возникающие ошибки.На картинке — основной синтаксис
async/await, принцип его работы, сравнение с цепочками .then() и другие полезные моменты.Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤7👍7
Склеивайте множество синхронных обновлений в одно!
Иногда функция может вызываться десятки раз за один проход синхронного кода.
Можно накопить изменения и запланировать обработку один раз:
Теперь даже серия вызовов обработается одной пачкой:
🔥 Такой подход объединяет множество быстрых обновлений в одну обработку, уменьшая лишние вычисления и нагрузку. Что крайне полезно для событий и часто обновляемых данных.
📣 JS Ready | #совет
Иногда функция может вызываться десятки раз за один проход синхронного кода.
Можно накопить изменения и запланировать обработку один раз:
const pending = new Set();
function update(id) {
pending.add(id);
scheduleFlush();
}
queueMicrotask() выполнит flush после текущего синхронного кода, но до перехода к следующей macrotask:function flush() {
scheduled = false;
process([...pending]);
pending.clear();
}Теперь даже серия вызовов обработается одной пачкой:
update(1);
update(2);
update(3);
// process([1, 2, 3]) — один раз
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10❤6👍5