Разбираем Web Workers, с помощью которых можно выполнять ресурсоёмкие задачи вне основного UI-потока: запускать фоновые вычисления, передавать данные между main thread и Worker, получать результаты, обрабатывать ошибки и управлять завершением Worker. Используется для тяжёлых вычислений и обработки больших объёмов данных без блокировки интерфейса.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍9🔥5
Выполняйте независимые операции без эффекта домино!
Если несколько операций не зависят друг от друга,
Для независимых задач используйте
Что полезно для пакетной отправки, фоновых задач и загрузки независимых данных: ошибка одной операции не скрывает успешные результаты остальных.
🔥 Если операции независимы, не позволяйте одной ошибке скрывать результат остальных — обрабатывайте каждую отдельно.
📣 JS Ready | #совет
Если несколько операций не зависят друг от друга,
Promise.all() может создать лишнюю связанность: одна ошибка отклоняет общий Promise, хотя остальные задачи продолжат выполняться и могут успешно завершиться.const users = await Promise.all(
ids.map(id => loadUser(id))
);
Для независимых задач используйте
Promise.allSettled() — он дождётся каждой и сохранит результат отдельно:const results = await Promise.allSettled(
ids.map(id => loadUser(id))
);
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
Что полезно для пакетной отправки, фоновых задач и загрузки независимых данных: ошибка одной операции не скрывает успешные результаты остальных.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍5🤝3❤1
В этой статье:
• Показывается, как с нуля собрать браузерного тамагочи на HTML, CSS и JavaScript — без фреймворков, npm и сборщиков;• Разбираются игровое состояние, жизненный цикл питомца, случайные события, мини-игра, коллекция и сохранение прогресса через localStorage;• Объясняется, как рисовать пиксельных персонажей программно через Canvas и создавать звуки через Web Audio API без готовых изображений и аудиофайлов.🔊 Продолжайте читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9🔥7👍5🤝2
Например,
REST используют для построения API, WebSocket — для двустороннего обмена данными, а gRPC — для взаимодействия между сервисами.На картинке — основные технологии и подходы, с которыми регулярно сталкиваются разработчики: REST, Webhooks, GraphQL, SOAP, WebSocket, gRPC, MQTT, AMQP, SSE, EDI и EDA. Кратко и наглядно показано, чем они отличаются, как работают и для каких задач применяются.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤5🤝5🔥2
HTTP передаёт данные между клиентом и сервером без шифрования, а HTTPS добавляет TLS — он аутентифицирует сервер, согласовывает ключи и защищает дальнейший обмен данными шифрованием.
На картинке наглядно показано, чем отличается обычное HTTP-соединение от HTTPS: от TCP-handshake до установки защищённого соединения и передачи данных.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤5🔥4🤝3
Используйте возвращаемое значение delete() вместо лишней проверки!
У
Поэтому вместо двойного поиска:
можно сразу использовать результат удаления:
То же самое работает с
Вы не выполняете сначала
🔥 Не проверяйте коллекцию перед удалением, если проверка нужна только ради условия —
📣 JS Ready | #совет
У
Map.delete() и Set.delete() есть полезное свойство: метод возвращает true, только если элемент действительно существовал и был удалён.Поэтому вместо двойного поиска:
if (cache.has(key)) {
cache.delete(key);
onRemoved(key);
}можно сразу использовать результат удаления:
if (cache.delete(key)) {
onRemoved(key);
}То же самое работает с
Set:if (activeUsers.delete(userId)) {
updateCounter();
}Вы не выполняете сначала
has(), а затем отдельный delete(). Сама операция удаления одновременно отвечает на вопрос, был ли элемент.delete() уже возвращает нужный результат.Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥8❤3🤝2
Подписывайтесь на событие только один раз через once!
У
Особенно полезно для одноразовых действий: завершения анимации, первого взаимодействия, загрузки ресурса или ожидания ответа.
Можно удобно превращать одноразовые события в
🔥 Для одноразового события используйте
📣 JS Ready | #совет
У
addEventListener() есть опция once: обработчик автоматически удаляется после первого срабатывания. Без ручного removeEventListener():button.addEventListener('click', handleClick, {
once: true
});Особенно полезно для одноразовых действий: завершения анимации, первого взаимодействия, загрузки ресурса или ожидания ответа.
element.addEventListener('transitionend', () => {
element.remove();
}, { once: true });Можно удобно превращать одноразовые события в
Promise:const once = (target, event) =>
new Promise(resolve =>
target.addEventListener(event, resolve, { once: true })
);
await once(video, 'ended');
console.log('Видео закончилось');
{ once: true }. Если ждёте одно из нескольких — снимайте оставшиеся обработчики через AbortController.Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤6🔥4
Как оплачивать зарубежные сервисы в 2026 году?
Можно бегать между посредниками и бояться блокировок после оплаты, а можно выпустить международную карту Lumio Pay и пользоваться любимыми сервисами без рисков.
— выпуск карты за 2 минуты
— лучший курс пополнения на рынке (у конкурентов на 20% выше)
— пополнение рублями или криптой
— чистые BIN карт, оплата без риска блокировок
Пока все ищут идеальное решение, оно у тебя перед глазами: @LumioPay
Можно бегать между посредниками и бояться блокировок после оплаты, а можно выпустить международную карту Lumio Pay и пользоваться любимыми сервисами без рисков.
— выпуск карты за 2 минуты
— лучший курс пополнения на рынке (у конкурентов на 20% выше)
— пополнение рублями или криптой
— чистые BIN карт, оплата без риска блокировок
Пока все ищут идеальное решение, оно у тебя перед глазами: @LumioPay
Почему forEach() не ждёт async-функцию?
Если операции должны выполняться последовательно, ожидание необходимо сделать частью самого цикла. Для этого подходит
Следующая итерация начнётся только после завершения предыдущей. Такой вариант нужен, когда важен порядок выполнения или операции зависят друг от друга.
Для независимых операций можно сформировать массив
Есть и важное следствие для обработки ошибок: внешний
Для управляемой обработки ошибки необходимо ожидать
🔥 Проблема не в
📣 JS Ready | #практика
forEach() не учитывает возвращаемое значение callback и не содержит механизма ожидания Promise. Поэтому передача async-callback не меняет модель выполнения метода: forEach() синхронно запускает callback для каждого элемента, не ожидая завершения созданных им асинхронных операций:const users = [1, 2, 3];
users.forEach(async (id) => {
await saveUser(id);
});
console.log("Готово");
"Готово" будет выведено до завершения saveUser(). Каждый вызов async-callback возвращает Promise, но forEach() эти Promise не ожидает и не собирает.Если операции должны выполняться последовательно, ожидание необходимо сделать частью самого цикла. Для этого подходит
for...of с await:for (const id of users) {
await saveUser(id);
}
console.log("Готово");Следующая итерация начнётся только после завершения предыдущей. Такой вариант нужен, когда важен порядок выполнения или операции зависят друг от друга.
Для независимых операций можно сформировать массив
Promise и дождаться их через Promise.all():await Promise.all(
users.map((id) => saveUser(id))
);
console.log("Готово");
Promise.all() успешно выполняется после выполнения всех переданных Promise и отклоняется, если хотя бы один из них завершается с ошибкой. При этом остальные уже запущенные операции автоматически не отменяются.Есть и важное следствие для обработки ошибок: внешний
try...catch вокруг forEach() не перехватит последующее отклонение Promise из async-callback:try {
users.forEach(async (id) => {
await saveUser(id);
});
} catch (error) {
console.error(error);
}Для управляемой обработки ошибки необходимо ожидать
Promise, представляющий выполнение асинхронных операций:try {
await Promise.all(
users.map((id) => saveUser(id))
);
} catch (error) {
console.error(error);
}async внутри forEach(), а в контракте самого метода: forEach() игнорирует возвращаемое значение callback и не ожидает Promise. Для последовательного выполнения используйте for...of с await, для конкурентного выполнения независимых операций — Promise.all().Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤6🔥6
Например,
REST используется для построения HTTP API, а OAuth 2.0 и JWT помогают организовать авторизацию и безопасную передачу данных.На картинке — основные темы API-разработки: методы и коды ответов, типы API, безопасность, документация, тестирование, интеграция и API Gateway.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍8❤4🤝1
Защищаем состояние от устаревших асинхронных результатов!
Порядок запуска асинхронных операций не определяет порядок их завершения. Если несколько вызовов обновляют одно состояние, более ранний запрос может завершиться позже и перезаписать актуальные данные:
Если
Когда отмена предыдущей операции невозможна или не требуется, актуальность результата можно контролировать с помощью монотонно увеличивающейся версии:
Каждый запуск получает собственную версию, а
При нескольких асинхронных этапах проверку следует выполнять после каждой границы, после которой выполнение может продолжиться с неактуальными данными:
Проверка версии не отменяет уже выполняющуюся работу. Она определяет только то, сохраняет ли результат право влиять на текущее состояние:
🔥 Такой version token реализует семантику
📣 JS Ready | #практика
Порядок запуска асинхронных операций не определяет порядок их завершения. Если несколько вызовов обновляют одно состояние, более ранний запрос может завершиться позже и перезаписать актуальные данные:
let state;
async function loadUser(id) {
const user = await fetchUser(id);
state = user;
}
loadUser(1);
loadUser(2);
Если
fetchUser(1) завершится после fetchUser(2), итоговым значением state станет пользователь 1, хотя последним был запущен loadUser(2).Когда отмена предыдущей операции невозможна или не требуется, актуальность результата можно контролировать с помощью монотонно увеличивающейся версии:
let state;
let version = 0;
async function loadUser(id) {
const currentVersion = ++version;
const user = await fetchUser(id);
if (currentVersion !== version) {
return;
}
state = user;
}
Каждый запуск получает собственную версию, а
version хранит версию последнего запуска. Если после await значения различаются, результат уже устарел и не должен изменять состояние.При нескольких асинхронных этапах проверку следует выполнять после каждой границы, после которой выполнение может продолжиться с неактуальными данными:
async function loadUser(id) {
const currentVersion = ++version;
const user = await fetchUser(id);
if (currentVersion !== version) {
return;
}
const permissions = await fetchPermissions(user.id);
if (currentVersion !== version) {
return;
}
state = { user, permissions };
}Проверка версии не отменяет уже выполняющуюся работу. Она определяет только то, сохраняет ли результат право влиять на текущее состояние:
loadUser(1); // version = 1
loadUser(2); // version = 2
// version = 1 игнорируется
// version = 2 может обновить state
latest invocation wins: завершение асинхронной операции отделяется от актуальности её результата и предотвращает запись устаревших данных.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤6🤝3👍1