JavaScript Ready | Программирование
8K subscribers
931 photos
60 videos
484 links
Авторский канал по разработке на JavaScript.
Ресурсы, обучения, задачи, шпаргалки.
Ежедневно информация пополняется!

Автор: @energy_c

Реклама на бирже: https://telega.in/c/javascript_readyy
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Нужно быстро обернуть текст или элемент в HTML-тег?

Htmltagwrap —
позволяет выделить любой фрагмент и за секунду обернуть его в нужный тег: div, span, section и любой другой, без ручного написания. Особенно удобно при верстке, работе с JSX и быстром редактировании разметки.

📣 JS Ready | #vscode
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍6🤝5😁1
📂 Напоминалка для работы с микросервисами!

Например, Load Balancer распределяет запросы между несколькими серверами, а API Gateway управляет доступом к API, маршрутизацией и ограничением запросов.

На картинке — основные различия между двумя важными компонентами современной микросервисной архитектуры.

Сохрани, чтобы не потерять!

📣 JS Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
👍106🔥4
Красивый диапазон дат без ручной склейки!

Очень частая задача в интерфейсе: показать период акции, бронь, событие или дедлайн.

Обычно начинают собирать строку руками:
`${start} - ${end}`


Но так быстро появляются проблемы с локалями, месяцами и повторяющимися частями даты.

В JS есть нативный метод formatRange() у Intl.DateTimeFormat.
fmt.formatRange(startDate, endDate)


Он сам форматирует диапазон по правилам выбранной локали.
fmt.formatRange(
new Date('2026-03-10'),
new Date('2026-03-14')
);


Если даты в одном месяце, результат будет компактным.
// 10–14 марта


А если диапазон пересекает месяцы — формат тоже останется корректным.
fmt.formatRange(
new Date('2026-03-30'),
new Date('2026-04-02')
);
// 30 марта – 2 апреля


🔥 Очень полезно для календарей, бронирований, акций, расписаний, событий и любого UI, где нужно показывать диапазоны дат без ручного форматирования.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🤝65
Разбираем разницу между Promise.all() и Promise.allSettled()!

Отличия между ними проявляются в момент ошибки. Если использовать 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() отвечает на другой вопрос: «Чем закончилась каждая операция?». Из-за этого они не заменяют друг друга и используются для разных сценариев.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥65
This media is not supported in your browser
VIEW IN TELEGRAM
💅 Frontend Stuff — коллекция полезных ресурсов для frontend-разработчиков!

На сайте собрана большая база материалов для JavaScript-разработчиков: статьи, библиотеки, фреймворки, инструменты, полезные сервисы и обучающие ресурсы. От базовых инструментов до React, Vue, Node.js и др. Отличный ресурс для веб-разработчиков, которые хотят ускорить работу или найти новые инструменты.

📌 Оставляю ссылочку: frontend-stuff.com

📣 JS Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
👍106🔥5
📂 Напоминалка по деструктуризации объектов!

При деструктуризации можно задавать значения по умолчанию — они применяются только когда значение свойства равно undefined (включая случай, когда свойства нет в объекте).

На картинке показано, как работает извлечение значений из объекта person, как подставляются fallback-значения при отсутствии данных, а также разбор кейсов с undefined, null и другими типами значений.

Сохрани, чтобы не потерять!

📣 JS Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥5🤝3
Сидеть и работать в корпорации — страшно, жизнь-то мимо проходит. Уходить строить бизнес — страшно, а вдруг прогорит. Один из вариантов — разрабатывать свой пет-проект по вечерам. Многие успешные компании, например, Twitter, создавались именно так. Это не значит, что ваш проект обязательно заработает миллиарды, но заработать больше, чем в найме, и получить ценный опыт — вполне реально.

Перед началом разработки появляется множество вопросов, например:

• Как выбрать идею для пет-проекта?
• Что нужно знать про маркетинг
• Как запуститься и довести до первых продаж не имея бюджета на рекламу?

В телеграм-канале «Твой пет проект», Михаил Табунов делится своим опытом с разработчиками и менеджерами.

Он рассказывает, где искать идею для нового проекта, что нужно знать о маркетинге, как запустить стартап и привлечь первых 10 клиентов, а также о многих других важных вещах.

Подписывайтесь на «Твой пет проект», получайте пользу от практиков рынка!
https://t.me/+8Frwa03ciVlhNTky
1
Сохраняем причину ошибки без потери контекста!

При обработке и повторном выбрасывании исключений исходный контекст ошибки может быть утерян, что усложняет диагностику.

Раньше приходилось вручную дописывать сообщение:
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 и хаоса в логах.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍74
This media is not supported in your browser
VIEW IN TELEGRAM
🐱 8 шпаргалок для веб-разработчика — полезная подборка по HTML, CSS, JavaScript, React и Git!

На странице собрана крутая подборка из 8 полезных шпаргалок для веб-разработчиков. Здесь справочники по HTML, CSS, Grid Layout, Flexbox, JavaScript, React и Git с примерами кода, схемами и наглядными объяснениями. Полезно для frontend-разработчиков: можно быстро освежить знания по вёрстке, JavaScript и др. инструментам.

📌 Оставляю ссылочку: highload.tech

📣 JS Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍7🤝51
Object.assign и spread: почему не копируются геттеры!

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 работают только с собственными перечисляемыми свойствами. Прототипные свойства в процесс не попадают.

🔥 Итог простой: оба механизма не копируют структуру свойств. Они читают значения, поэтому геттеры срабатывают в момент копирования, а в новый объект попадает уже результат, а не логика свойства.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍7🔥6
📂 Напоминалка для работы с датами!

Например, new Date() создаёт объект даты, getFullYear() возвращает текущий год, а toISOString() помогает получить дату в удобном формате для API и хранения данных.

На картинке — основные методы Date, которые пригодятся для создания, изменения, форматирования и получения значений даты.

Сохрани, чтобы не потерять!

📣 JS Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥135👍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 - рекомендую подписаться🔗
1
Генерируем UUID без библиотек!

Очень частая задача: создать уникальный 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.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍177🤝4🔥2
Надоело долбить LeetCode в пустоту? 🎮

Девстанция — это не очередной список задач. Это RPG для программиста:

🕸 Паутина вместо списка. Каждая задача — узел на графе. Открываешь одни — открываешь путь к другим. Панорамируешь, зумишь, видишь прогресс физически. Skill Tree в мире кодинга.

🏆 Сезоны. 180 дней на прохождение паутины. В конце — нагрды и подведение итогов. Каждый сезон — перерождение. Никто не стартует с форой.

🔥 Геймификация. Стрики, ежедневные челленджи, достижения, рейтинги за сегодня/вчера/неделю/сезон, графики активности — ощути прилив азарта.

👥 Лента событий. Видишь, кто только что решил задачу, кто взял золото дня, кто выбил ачивку. Ты не один в тёмной комнате.

Первый сезон уже идёт. Заходи в паутину 🕸

👉 Решай задачи на dev-station.ru
🔥31
AbortSignal.timeout() — встроенный способ задавать таймаут для fetch!

У 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, сейчас во многих случаях её можно упростить.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍6🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
🤔 HTML5Book — большой учебник по HTML, CSS и JavaScript!

На сайте собрана большая база материалов по веб-разработке: подробные уроки по HTML5, CSS3, JavaScript и jQuery, а также удобные справочники по HTML- и CSS-свойствам. Здесь можно найти разбор тегов, форм, анимаций, Flexbox, Grid, DOM и других ключевых технологий фронтенда. Большое количество практических примеров, готовых решений и UI-эффектов для интерфейсов.

📌 Оставляю ссылочку: html5book.ru

📣 JS Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍65
Берём первый успешный async-результат!

Иногда есть несколько источников данных: основной 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);
}


🔥 Полезно для резервных API, CDN-зеркал, запасных адресов сервера, загрузки конфигурации и любой логики, где важен первый успешный результат.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
16🔥5👍4
Парсим URL без try...catch!

Очень часто нужно проверить, является ли строка корректным 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 и роутингом.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍127🔥5
📂 Напоминалка по массивам (Array)!

Например, push() добавляет элементы в массив, map() создаёт новый после обработки данных, а filter() помогает отбирать нужные значения.

На картинке — 18 практических задач с решениями по работе с массивами JavaScript: создание, изменение, поиск, удаление, сортировка, объединение, преобразование и обработка данных.

Сохрани, чтобы не потерять!

📣 JS Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
10🔥5👍3
delete: почему его осторожно используют в производительном коде!

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 убирает связь между объектом и свойством, но не уничтожает данные, на которые ещё кто-то ссылается.

🔥 Если вы работаете с большими массивами однотипных объектов, большим количеством данных или производительными участками кода, стоит помнить: частое изменение структуры объектов может влиять на оптимизации JavaScript-движка.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍105🔥5
Клонирование объектов без JSON.stringify!

Очень часто для копии объекта используют старый приём:
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-клонированию для глубоких копий объектов без сторонних библиотек и скрытых потерь данных.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥7🤝4