Разбираем разницу между Promise.all() и Promise.allSettled()!
Отличия между ними проявляются в момент ошибки. Если использовать
При этом остальные операции не отменяются. Запросы, таймеры и прочая асинхронщина продолжают выполняться. Просто
Когда нужен результат каждой операции независимо от исхода, есть
На выходе получится массив объектов со статусом каждого промиса:
Это удобно для независимых задач. Например, страница загружает профиль пользователя, уведомления и рекомендации. Если рекомендации упали с ошибкой, профиль и уведомления всё равно можно показать. Или пакетная обработка:
После выполнения можно отдельно посмотреть успешные и неуспешные операции, собрать статистику или повторно обработать ошибки.
🔥
📣 JS Ready | #практика
Отличия между ними проявляются в момент ошибки. Если использовать
Promise.all(), то достаточно одного rejected-промиса, чтобы весь результат тоже стал rejected:await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
]);
При этом остальные операции не отменяются. Запросы, таймеры и прочая асинхронщина продолжают выполняться. Просто
Promise.all() больше не ждёт общий успешный результат.Когда нужен результат каждой операции независимо от исхода, есть
Promise.allSettled():const results = await Promise.allSettled([
fetchUser(),
fetchPosts(),
fetchComments()
]);
На выходе получится массив объектов со статусом каждого промиса:
[
{ status: "fulfilled", value: {...} },
{ status: "rejected", reason: Error(...) },
{ status: "fulfilled", value: [...] }
]
Это удобно для независимых задач. Например, страница загружает профиль пользователя, уведомления и рекомендации. Если рекомендации упали с ошибкой, профиль и уведомления всё равно можно показать. Или пакетная обработка:
const results = await Promise.allSettled(
users.map(user => sendEmail(user))
);
После выполнения можно отдельно посмотреть успешные и неуспешные операции, собрать статистику или повторно обработать ошибки.
Promise.all() отвечает на вопрос: «Все операции завершились успешно?». Promise.allSettled() отвечает на другой вопрос: «Чем закончилась каждая операция?». Из-за этого они не заменяют друг друга и используются для разных сценариев.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥6❤5
This media is not supported in your browser
VIEW IN TELEGRAM
На сайте собрана большая база материалов для JavaScript-разработчиков: статьи, библиотеки, фреймворки, инструменты, полезные сервисы и обучающие ресурсы. От базовых инструментов до React, Vue, Node.js и др. Отличный ресурс для веб-разработчиков, которые хотят ускорить работу или найти новые инструменты.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤6🔥5
При деструктуризации можно задавать значения по умолчанию — они применяются только когда значение свойства равно undefined (включая случай, когда свойства нет в объекте).
На картинке показано, как работает извлечение значений из объекта person, как подставляются fallback-значения при отсутствии данных, а также разбор кейсов с undefined, null и другими типами значений.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥5🤝3
Сидеть и работать в корпорации — страшно, жизнь-то мимо проходит. Уходить строить бизнес — страшно, а вдруг прогорит. Один из вариантов — разрабатывать свой пет-проект по вечерам. Многие успешные компании, например, Twitter, создавались именно так. Это не значит, что ваш проект обязательно заработает миллиарды, но заработать больше, чем в найме, и получить ценный опыт — вполне реально.
Перед началом разработки появляется множество вопросов, например:
• Как выбрать идею для пет-проекта?
• Что нужно знать про маркетинг
• Как запуститься и довести до первых продаж не имея бюджета на рекламу?
В телеграм-канале «Твой пет проект», Михаил Табунов делится своим опытом с разработчиками и менеджерами.
Он рассказывает, где искать идею для нового проекта, что нужно знать о маркетинге, как запустить стартап и привлечь первых 10 клиентов, а также о многих других важных вещах.
Подписывайтесь на «Твой пет проект», получайте пользу от практиков рынка!
https://t.me/+8Frwa03ciVlhNTky
Перед началом разработки появляется множество вопросов, например:
• Как выбрать идею для пет-проекта?
• Что нужно знать про маркетинг
• Как запуститься и довести до первых продаж не имея бюджета на рекламу?
В телеграм-канале «Твой пет проект», Михаил Табунов делится своим опытом с разработчиками и менеджерами.
Он рассказывает, где искать идею для нового проекта, что нужно знать о маркетинге, как запустить стартап и привлечь первых 10 клиентов, а также о многих других важных вещах.
Подписывайтесь на «Твой пет проект», получайте пользу от практиков рынка!
https://t.me/+8Frwa03ciVlhNTky
Telegram
Твой пет проект
Канал про то, как создать свой маленький свечной заводик
Пишу про:
- Запуски и как сделать первые 10 продаж
- Прожарка идей
- Кейсы роста и ведения проекта параллельно с работой
Автор - Михаил Табунов - @bossofyourboss
Связь @to_baza_education
Пишу про:
- Запуски и как сделать первые 10 продаж
- Прожарка идей
- Кейсы роста и ведения проекта параллельно с работой
Автор - Михаил Табунов - @bossofyourboss
Связь @to_baza_education
❤1
Сохраняем причину ошибки без потери контекста!
При обработке и повторном выбрасывании исключений исходный контекст ошибки может быть утерян, что усложняет диагностику.
Раньше приходилось вручную дописывать сообщение:
Так стек и тип исходной ошибки легко теряются.
В JavaScript есть нативный
Теперь верхняя ошибка объясняет контекст, а
Это удобно, когда ошибка проходит через несколько уровней: чтение файла, парсинг JSON, валидация, инициализация приложения.
🔥
📣 JS Ready | #совет
При обработке и повторном выбрасывании исключений исходный контекст ошибки может быть утерян, что усложняет диагностику.
Раньше приходилось вручную дописывать сообщение:
throw new Error('Config loading failed: ' + err.message);Так стек и тип исходной ошибки легко теряются.
В JavaScript есть нативный
Error.cause.throw new Error('Не удалось загрузить конфиг', { cause: err });Теперь верхняя ошибка объясняет контекст, а
cause хранит настоящую причину.error.cause
Это удобно, когда ошибка проходит через несколько уровней: чтение файла, парсинг JSON, валидация, инициализация приложения.
try {
JSON.parse('{bad json}');
} catch (err) {
throw new Error('Config parse failed', { cause: err });
}Error.cause помогает строить цепочки ошибок без склейки строк, потери stack trace и хаоса в логах.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍7❤4
This media is not supported in your browser
VIEW IN TELEGRAM
На странице собрана крутая подборка из 8 полезных шпаргалок для веб-разработчиков. Здесь справочники по HTML, CSS, Grid Layout, Flexbox, JavaScript, React и Git с примерами кода, схемами и наглядными объяснениями. Полезно для frontend-разработчиков: можно быстро освежить знания по вёрстке, JavaScript и др. инструментам.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍7🤝5❤1
Object.assign и spread: почему не копируются геттеры!
Пока объект состоит только из обычных полей, никакой разницы не видно.
Проблема появляется, когда в объекте есть геттеры.
Когда вызывается
Дальше результат просто записывается в новый объект как обычное поле.
В копии уже нет никакого геттера, там обычное значение, полученное в момент копирования.
В оригинальном объекте всё иначе — там сохраняется сам
Он тоже читает свойства, поэтому геттер вызывается в момент создания нового объекта, а не переносится как структура.
Если нужно сохранить именно поведение объекта вместе с геттерами, используют копирование дескрипторов.
В этом варианте ничего не вычисляется заранее — переносится описание свойств как есть. И
🔥 Итог простой: оба механизма не копируют структуру свойств. Они читают значения, поэтому геттеры срабатывают в момент копирования, а в новый объект попадает уже результат, а не логика свойства.
📣 JS Ready | #практика
Object.assign и spread часто используют как быстрый способ скопировать объект, и на простых структурах всё действительно выглядит как прямое копирование значений.const user = {
name: "Анна"
};
const copy = Object.assign({}, user);
console.log(copy);
Пока объект состоит только из обычных полей, никакой разницы не видно.
Проблема появляется, когда в объекте есть геттеры.
const user = {
firstName: "Анна",
lastName: "Иванова",
get fullName() {
console.log("getter called");
return `${this.firstName} ${this.lastName}`;
}
};
fullName здесь не хранит значение. Это вычисляемое свойство, и оно выполняется в момент чтения.Когда вызывается
Object.assign, он проходит по собственным перечисляемым свойствам и читает каждое через [[Get]]. В этот момент геттер реально срабатывает.const copy = Object.assign({}, user);
Дальше результат просто записывается в новый объект как обычное поле.
console.log(Object.getOwnPropertyDescriptor(copy, "fullName"));
В копии уже нет никакого геттера, там обычное значение, полученное в момент копирования.
{
value: "Анна Иванова",
writable: true,
enumerable: true,
configurable: true
}
В оригинальном объекте всё иначе — там сохраняется сам
accessor, а не результат его выполнения.console.log(Object.getOwnPropertyDescriptor(user, "fullName"));
{
get: [Function],
set: undefined,
enumerable: true,
configurable: true
}
spread работает ровно так же.const copy = {
...user
};
Он тоже читает свойства, поэтому геттер вызывается в момент создания нового объекта, а не переносится как структура.
Если нужно сохранить именно поведение объекта вместе с геттерами, используют копирование дескрипторов.
const copy = Object.defineProperties(
{},
Object.getOwnPropertyDescriptors(user)
);
В этом варианте ничего не вычисляется заранее — переносится описание свойств как есть. И
Object.assign, и spread работают только с собственными перечисляемыми свойствами. Прототипные свойства в процесс не попадают.Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍7🔥6
Например,
new Date() создаёт объект даты, getFullYear() возвращает текущий год, а toISOString() помогает получить дату в удобном формате для API и хранения данных.На картинке — основные методы Date, которые пригодятся для создания, изменения, форматирования и получения значений даты.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤5👍5
Слышали о BitGN E-commerce AI Agent Challenge?
ECOM1 - бенчмарк агентной коммерции. AI-агенты работают в симуляции интернет-магазина: корзины, заказы, чекаут и т.д.
Меня зацепил самый умный из быстрых агентов - Exoskeleton от Ильяса Салихова, CTO RetailCRM. Взял 1 место в Speed и топ Live PROD на gpt-5.4-mini (в 6 раз дешевле gpt-5.5 конкурентов).
Секрет в архитектуре:
• Mini - слабое тело, вокруг каркас из кода и nano-моделей. Данные грузятся до старта, nano разбирает намерения: фрод, манипуляция, подмена личности.
• Безопасность зашита в код, решения принимает логика. Ссылки на регламенты собираются сами, финальная nano причёсывает ответ.
• Тяжёлая логика в коде. Модель делает только то, в чём сильна.
Итог: обошла старшие модели по очкам и скорости.
Полная статья со схемами от Ильяса. А ещё у него канал про инженерию и AI - рекомендую подписаться🔗
ECOM1 - бенчмарк агентной коммерции. AI-агенты работают в симуляции интернет-магазина: корзины, заказы, чекаут и т.д.
Меня зацепил самый умный из быстрых агентов - Exoskeleton от Ильяса Салихова, CTO RetailCRM. Взял 1 место в Speed и топ Live PROD на gpt-5.4-mini (в 6 раз дешевле gpt-5.5 конкурентов).
Секрет в архитектуре:
• Mini - слабое тело, вокруг каркас из кода и nano-моделей. Данные грузятся до старта, nano разбирает намерения: фрод, манипуляция, подмена личности.
• Безопасность зашита в код, решения принимает логика. Ссылки на регламенты собираются сами, финальная nano причёсывает ответ.
• Тяжёлая логика в коде. Модель делает только то, в чём сильна.
Итог: обошла старшие модели по очкам и скорости.
Полная статья со схемами от Ильяса. А ещё у него канал про инженерию и AI - рекомендую подписаться🔗
❤1
Генерируем UUID без библиотек!
Очень частая задача: создать уникальный id для пользователя, заказа, файла или любой сущности.
Раньше для этого почти всегда тянули библиотеки типа uuid.
Хотя в современном JavaScript это уже есть нативно.
Метод сразу возвращает криптографически стойкий UUID v4.
Результат выглядит так:
Подходит для случаев, где нужен уникальный идентификатор: id сущностей, ключи записей, request/session id, временные идентификаторы.
Для секретных токенов (reset password, API tokens) лучше использовать
В браузере работает в secure context — HTTPS или localhost.
🔥
📣 JS Ready | #совет
Очень частая задача: создать уникальный id для пользователя, заказа, файла или любой сущности.
Раньше для этого почти всегда тянули библиотеки типа uuid.
import { v4 as uuid } from 'uuid';Хотя в современном JavaScript это уже есть нативно.
crypto.randomUUID()
Метод сразу возвращает криптографически стойкий UUID v4.
const id = crypto.randomUUID();
Результат выглядит так:
36b8f84d-df4e-4d49-b662-bcde71a8764fПодходит для случаев, где нужен уникальный идентификатор: id сущностей, ключи записей, request/session id, временные идентификаторы.
Для секретных токенов (reset password, API tokens) лучше использовать
crypto.getRandomValues() или crypto.randomBytes().В браузере работает в secure context — HTTPS или localhost.
crypto.randomUUID() — простой способ получать уникальные id.Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤7🤝4🔥2
Надоело долбить LeetCode в пустоту? 🎮
Девстанция — это не очередной список задач. Это RPG для программиста:
🕸 Паутина вместо списка. Каждая задача — узел на графе. Открываешь одни — открываешь путь к другим. Панорамируешь, зумишь, видишь прогресс физически. Skill Tree в мире кодинга.
🏆 Сезоны. 180 дней на прохождение паутины. В конце — нагрды и подведение итогов. Каждый сезон — перерождение. Никто не стартует с форой.
🔥 Геймификация. Стрики, ежедневные челленджи, достижения, рейтинги за сегодня/вчера/неделю/сезон, графики активности — ощути прилив азарта.
👥 Лента событий. Видишь, кто только что решил задачу, кто взял золото дня, кто выбил ачивку. Ты не один в тёмной комнате.
Первый сезон уже идёт. Заходи в паутину 🕸
👉 Решай задачи на dev-station.ru
Девстанция — это не очередной список задач. Это RPG для программиста:
🕸 Паутина вместо списка. Каждая задача — узел на графе. Открываешь одни — открываешь путь к другим. Панорамируешь, зумишь, видишь прогресс физически. Skill Tree в мире кодинга.
🏆 Сезоны. 180 дней на прохождение паутины. В конце — нагрды и подведение итогов. Каждый сезон — перерождение. Никто не стартует с форой.
🔥 Геймификация. Стрики, ежедневные челленджи, достижения, рейтинги за сегодня/вчера/неделю/сезон, графики активности — ощути прилив азарта.
👥 Лента событий. Видишь, кто только что решил задачу, кто взял золото дня, кто выбил ачивку. Ты не один в тёмной комнате.
Первый сезон уже идёт. Заходи в паутину 🕸
👉 Решай задачи на dev-station.ru
🔥3❤1
AbortSignal.timeout() — встроенный способ задавать таймаут для fetch!
У
Долгое время стандартным решением был
Подход полностью рабочий, но даже для базового таймаута требует дополнительной логики: создание контроллера, запуск таймера и последующую очистку.
С появлением
В этом случае
Для типового случая этого обычно достаточно. Обработка ошибок при этом остаётся стандартной.
Если запрос был прерван через
Механизм работает не только с
Отдельно стоит упомянуть
В таком случае операция завершится при срабатывании первого сигнала — либо по ручной отмене, либо по таймауту.
🔥 Если в проекте до сих пор используется ручная реализация таймаута через
📣 JS Ready | #практика
У
fetch нет встроенного параметра для ограничения времени ожидания. Если сервер отвечает слишком долго или соединение зависает, запрос может оставаться активным неопределённое время.Долгое время стандартным решением был
AbortController в сочетании с setTimeout().const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, 5000);
try {
const response = await fetch("/api/users", {
signal: controller.signal
});
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
} finally {
clearTimeout(timeoutId);
}
Подход полностью рабочий, но даже для базового таймаута требует дополнительной логики: создание контроллера, запуск таймера и последующую очистку.
С появлением
AbortSignal.timeout() эта задача решается значительно проще.const response = await fetch("/api/users", {
signal: AbortSignal.timeout(5000)
});
const data = await response.json();
console.log(data);
В этом случае
AbortSignal автоматически перейдёт в состояние aborted через указанное количество миллисекунд, после чего операция будет отменена.Для типового случая этого обычно достаточно. Обработка ошибок при этом остаётся стандартной.
try {
const response = await fetch("/api/users", {
signal: AbortSignal.timeout(5000)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === "TimeoutError") {
console.log("Время ожидания истекло");
} else {
console.error(error);
}
}
Если запрос был прерван через
AbortSignal.timeout(), ошибка обычно имеет имя TimeoutError. Если отмена произошла вручную через AbortController.abort(), чаще это будет AbortError. Это даёт возможность разделять сценарии таймаута и ручной отмены на уровне обработки ошибок.Механизм работает не только с
fetch. Любой API с поддержкой AbortSignal может использовать тот же подход.await someAsyncOperation({
signal: AbortSignal.timeout(10000)
});
Отдельно стоит упомянуть
AbortSignal.any(), который позволяет объединять несколько сигналов отмены.const controller = new AbortController();
const signal = AbortSignal.any([
controller.signal,
AbortSignal.timeout(5000)
]);
await fetch("/api/users", { signal });
В таком случае операция завершится при срабатывании первого сигнала — либо по ручной отмене, либо по таймауту.
AbortController и setTimeout, сейчас во многих случаях её можно упростить.Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍6🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
На сайте собрана большая база материалов по веб-разработке: подробные уроки по HTML5, CSS3, JavaScript и jQuery, а также удобные справочники по HTML- и CSS-свойствам. Здесь можно найти разбор тегов, форм, анимаций, Flexbox, Grid, DOM и других ключевых технологий фронтенда. Большое количество практических примеров, готовых решений и UI-эффектов для интерфейсов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍6❤5
Берём первый успешный async-результат!
Иногда есть несколько источников данных: основной API, резервный endpoint или кеш. Нужно взять тот, который первым успешно ответит, а не просто завершится первым.
Для этого есть
Он вернёт первый выполненный
В отличие от
Если упали все варианты, тогда будет
🔥 Полезно для резервных API, CDN-зеркал, запасных адресов сервера, загрузки конфигурации и любой логики, где важен первый успешный результат.
📣 JS Ready | #совет
Иногда есть несколько источников данных: основной API, резервный endpoint или кеш. Нужно взять тот, который первым успешно ответит, а не просто завершится первым.
Для этого есть
Promise.any().Promise.any([main, backup, cache])
Он вернёт первый выполненный
Promise и проигнорирует те, которые упали.const response = await Promise.any([
fetch('/api/main'),
fetch('/api/backup')
]);
В отличие от
Promise.race(), он не падает из-за первого reject.Promise.race([...]) // первый завершился — и всё
Promise.any([...]) // ждёт первый успешный
Если упали все варианты, тогда будет
AggregateError.catch (err) {
console.log(err.errors);
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤16🔥5👍4
Парсим URL без try...catch!
Очень часто нужно проверить, является ли строка корректным URL. Обычно для этого используют конструктор URL, но он выбрасывает исключение.
Из-за этого приходится оборачивать код в
Теперь в JavaScript появился
Если строка содержит корректный URL, метод вернёт объект URL.
Если строка некорректна — вместо исключения вернётся
Это позволяет писать обычные проверки без лишней обработки ошибок.
🔥
📣 JS Ready | #совет
Очень часто нужно проверить, является ли строка корректным URL. Обычно для этого используют конструктор URL, но он выбрасывает исключение.
new URL(input);
Из-за этого приходится оборачивать код в
try...catch.Теперь в JavaScript появился
URL.parse().const url = URL.parse(input);
Если строка содержит корректный URL, метод вернёт объект URL.
console.log(url.hostname);
Если строка некорректна — вместо исключения вернётся
null.URL.parse('not a url');
// nullЭто позволяет писать обычные проверки без лишней обработки ошибок.
URL.parse() — удобный способ валидировать и разбирать URL без try...catch, что особенно полезно при работе с пользовательским вводом, API и роутингом.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤7🔥5
Например,
push() добавляет элементы в массив, map() создаёт новый после обработки данных, а filter() помогает отбирать нужные значения.На картинке — 18 практических задач с решениями по работе с массивами JavaScript: создание, изменение, поиск, удаление, сортировка, объединение, преобразование и обработка данных.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10🔥5👍3
delete: почему его осторожно используют в производительном коде!
Например:
Выглядит просто, и в большинстве обычных случаев так и есть. Если вы удалили одно свойство из небольшого объекта — скорее всего, никакой разницы по производительности не заметите.
Но ситуация меняется, когда такие операции начинают выполняться тысячи раз подряд или применяются к большим коллекциям объектов.
JavaScript-движки вроде V8 оптимизируют работу с объектами, которые имеют одинаковую структуру. Когда объекты выглядят одинаково, движку проще хранить информацию о них и быстрее выполнять операции доступа к свойствам.
Например:
Все объекты здесь имеют одинаковую форму: у каждого есть
Но если начать менять структуру объектов:
один объект уже отличается от остальных.
Если сделать это массово:
коллекция становится неоднородной.
Для разработчика это обычное изменение данных, но для JavaScript-движка это уже разные варианты объектов, которые сложнее оптимизировать. Особенно это может быть заметно в местах, где вы постоянно работаете с большими массивами одинаковых объектов.
Например:
Допустим, дальше нужно убрать цену у всех товаров:
Технически код правильный. Но если это горячий участок приложения, где такой цикл выполняется часто и на больших объёмах данных, можно оставить структуру объектов прежней:
Теперь поле остаётся частью объекта:
А после
Разница такая:
Например, когда нужно удалить ключ из кэша:
Здесь объект используется как хранилище ключей, и удаление свойства полностью соответствует задаче.
Если структура данных постоянно меняется, часто используют
Ещё один момент, который часто вызывает вопросы:
Например:
После удаления
🔥 Если вы работаете с большими массивами однотипных объектов, большим количеством данных или производительными участками кода, стоит помнить: частое изменение структуры объектов может влиять на оптимизации JavaScript-движка.
📣 JS Ready | #практика
delete — стандартный оператор JavaScript для удаления свойств объекта. На практике он встречается довольно часто: удалить временное поле, убрать ненужный параметр перед отправкой данных, очистить объект после выполнения операции.Например:
const user = {
name: "Анна",
age: 25,
role: "admin"
};
delete user.age;
console.log(user);
// { name: "Анна", role: "admin" }
Выглядит просто, и в большинстве обычных случаев так и есть. Если вы удалили одно свойство из небольшого объекта — скорее всего, никакой разницы по производительности не заметите.
Но ситуация меняется, когда такие операции начинают выполняться тысячи раз подряд или применяются к большим коллекциям объектов.
JavaScript-движки вроде V8 оптимизируют работу с объектами, которые имеют одинаковую структуру. Когда объекты выглядят одинаково, движку проще хранить информацию о них и быстрее выполнять операции доступа к свойствам.
Например:
const users = [
{
id: 1,
name: "Анна",
age: 25
},
{
id: 2,
name: "Иван",
age: 30
},
{
id: 3,
name: "Олег",
age: 28
}
];
Все объекты здесь имеют одинаковую форму: у каждого есть
id, name и age. Такой подход часто встречается в реальных приложениях: списки пользователей, товары, сообщения, записи из базы данных.Но если начать менять структуру объектов:
delete users[0].age;
один объект уже отличается от остальных.
Если сделать это массово:
delete users[0].age;
delete users[1].age;
delete users[2].age;
коллекция становится неоднородной.
Для разработчика это обычное изменение данных, но для JavaScript-движка это уже разные варианты объектов, которые сложнее оптимизировать. Особенно это может быть заметно в местах, где вы постоянно работаете с большими массивами одинаковых объектов.
Например:
const products = data.map(item => ({
id: item.id,
title: item.title,
price: item.price
}));
Допустим, дальше нужно убрать цену у всех товаров:
for (const product of products) {
delete product.price;
}
Технически код правильный. Но если это горячий участок приложения, где такой цикл выполняется часто и на больших объёмах данных, можно оставить структуру объектов прежней:
for (const product of products) {
product.price = undefined;
}
Теперь поле остаётся частью объекта:
console.log("price" in products[0]);
// true
А после
delete оно полностью исчезает:delete products[0].price;
console.log("price" in products[0]);
// false
Разница такая:
undefined — свойство осталось, изменилось только значение; delete — свойство удалено из объекта полностью. Но из этого не следует, что delete нужно запрещать, есть много случаев, где он является правильным решением.Например, когда нужно удалить ключ из кэша:
const cache = {};
cache.users = data;
delete cache.users;
Здесь объект используется как хранилище ключей, и удаление свойства полностью соответствует задаче.
Если структура данных постоянно меняется, часто используют
Map:const cache = new Map();
cache.set("users", data);
cache.delete("users");
Map хорошо подходит для динамических коллекций: кэшей, словарей, временных хранилищ и таблиц соответствий, где ключи регулярно добавляются и удаляются.Ещё один момент, который часто вызывает вопросы:
delete удаляет только свойство объекта, но не сам объект из памяти.Например:
const user = {
settings: {
theme: "dark"
}
};
const settings = user.settings;
delete user.settings;
console.log(settings.theme);
// dark
После удаления
user.settings объект всё ещё существует, потому что переменная settings продолжает хранить на него ссылку. То есть delete убирает связь между объектом и свойством, но не уничтожает данные, на которые ещё кто-то ссылается.Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤5🔥5
Клонирование объектов без JSON.stringify!
Очень часто для копии объекта используют старый приём:
Но это подходит только для простых JSON-данных и может неожиданно менять структуру объекта.
В современном JavaScript есть нативный способ —
Он создаёт полноценную глубокую копию, сохраняя типы данных.
После копирования остаются настоящие
Также
🔥
📣 JS Ready | #совет
Очень часто для копии объекта используют старый приём:
const copy = JSON.parse(JSON.stringify(obj));
Но это подходит только для простых JSON-данных и может неожиданно менять структуру объекта.
В современном JavaScript есть нативный способ —
structuredClone():const copy = structuredClone(original);
Он создаёт полноценную глубокую копию, сохраняя типы данных.
const user = {
created: new Date(),
roles: new Set(['admin'])
};
const clone = structuredClone(user);После копирования остаются настоящие
Date и Set, а не преобразованные значения.Также
structuredClone() умеет работать с циклическими ссылками:const obj = {};
obj.self = obj;
const copy = structuredClone(obj);structuredClone() — замена JSON-клонированию для глубоких копий объектов без сторонних библиотек и скрытых потерь данных.Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥7🤝4
В этой статье:
• Простым языком объясняется, что такое API и зачем он нужен в современных приложениях;
• На примере маркетплейса показывается, как программы обмениваются данными между собой;
• Разбирается разница между UI, frontend, backend и API;
• Показывается, как работают endpoint’ы, JSON и HTTP-запросы;🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥5🤝3
Шпаргалка по циклам в JavaScript!
Например,
На картинке основные конструкции циклов: классический
Сохрани, чтобы не потерять!
📣 JS Ready | #ресурс
Например,
for подходит для ситуаций, когда заранее известно количество итераций, а for...of является способом перебора значений массивов, строк и других итерируемых объектов.На картинке основные конструкции циклов: классический
for, циклы с предварительной и постусловной проверкой while и do...while, перебор коллекций через for...of и for...in, метод массива forEach(), управление выполнением, а также примеры вложенных циклов.Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤6🔥6🤝2
Разбираем, как сделать функцию ограничения значения в диапазоне!
В реальных приложениях часто нужно контролировать значения: громкость плеера, процент выполнения, координаты элемента, количество элементов на странице или любые пользовательские настройки.
Обычно такие проверки пишут через несколько
Создаём функцию
Если значение меньше min, вернётся минимальная граница. Если больше max — максимальная. Во всех остальных случаях вернётся исходное значение. Проверяем работу функции
В первом случае значение превышает максимум, поэтому результат становится 100. Во втором значение ниже минимума и заменяется на 0. Третий вариант уже находится внутри диапазона и остаётся без изменений.
Ограничиваем прогресс загрузки
Даже если данные пришли с ошибкой и сервер вернул значение больше 100, в интерфейс попадёт корректный процент. Такой подход часто используют перед отображением прогресса, размеров, процентов или других числовых параметров.
Ограничиваем пользовательский ввод
Например, пользователь может ввести 10000 или отрицательное число. Перед отправкой запроса значение приводится к допустимому диапазону:
Это помогает держать бизнес-логику предсказуемой и не размазывать проверки по всему коду.
Ограничиваем координаты элемента
Такой вариант полезен для drag-and-drop, игровых механик или любых интерфейсов, где объект не должен выходить за пределы контейнера. Вместо постоянных проверок границ используется одна универсальная функция.
Добавляем проверку некорректного диапазона
Если перепутать границы:
код сразу сообщит об ошибке. Для небольших скриптов такая проверка обычно не нужна, но в общих утилитах проекта она помогает быстрее находить проблемы.
🔥
📣 JS Ready | #практика
В реальных приложениях часто нужно контролировать значения: громкость плеера, процент выполнения, координаты элемента, количество элементов на странице или любые пользовательские настройки.
Обычно такие проверки пишут через несколько
if, но одинаковая логика быстро начинает повторяться. Для таких задач удобно использовать небольшой паттерн clamp() — он оставляет значение внутри заданного диапазона.Создаём функцию
clampfunction clamp(value, min, max) {
return Math.min(
Math.max(value, min),
max
);
}
clamp() принимает три значения: само число, минимальную и максимальную границу.Если значение меньше min, вернётся минимальная граница. Если больше max — максимальная. Во всех остальных случаях вернётся исходное значение. Проверяем работу функции
console.log(clamp(150, 0, 100));
// 100
console.log(clamp(-20, 0, 100));
// 0
console.log(clamp(50, 0, 100));
// 50
В первом случае значение превышает максимум, поэтому результат становится 100. Во втором значение ниже минимума и заменяется на 0. Третий вариант уже находится внутри диапазона и остаётся без изменений.
Ограничиваем прогресс загрузки
const serverProgress = 135;
const progress = clamp(
serverProgress,
0,
100
);
console.log(progress);
// 100
Даже если данные пришли с ошибкой и сервер вернул значение больше 100, в интерфейс попадёт корректный процент. Такой подход часто используют перед отображением прогресса, размеров, процентов или других числовых параметров.
Ограничиваем пользовательский ввод
const userLimit = Number(input.value);
const limit = clamp(
userLimit,
10,
100
);
fetch(`/api/items?limit=${limit}`);
Например, пользователь может ввести 10000 или отрицательное число. Перед отправкой запроса значение приводится к допустимому диапазону:
10 <= limit <= 100
Это помогает держать бизнес-логику предсказуемой и не размазывать проверки по всему коду.
Ограничиваем координаты элемента
const x = clamp(
mouseX,
0,
containerWidth
);
const y = clamp(
mouseY,
0,
containerHeight
);
Такой вариант полезен для drag-and-drop, игровых механик или любых интерфейсов, где объект не должен выходить за пределы контейнера. Вместо постоянных проверок границ используется одна универсальная функция.
Добавляем проверку некорректного диапазона
function clamp(value, min, max) {
if (min > max) {
throw new Error(
"min cannot be greater than max"
);
}
return Math.min(
Math.max(value, min),
max
);
}
Если перепутать границы:
clamp(50, 100, 0);
код сразу сообщит об ошибке. Для небольших скриптов такая проверка обычно не нужна, но в общих утилитах проекта она помогает быстрее находить проблемы.
clamp() — небольшая функция, но она хорошо подходит для большого количества задач. Вместо повторяющихся условий с if появляется единый способ работы с диапазонами, который проще поддерживать и использовать в разных частях приложения.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍6🔥5