Будни разработчика
14.5K subscribers
1.23K photos
358 videos
7 files
2.1K links
Блог Lead JS-разработчика из Хельсинки
Автор: @bekharsky

По рекламе: https://telega.in/channels/htmlshit/card?r=GLOiHluU или https://t.iss.one/it_adv

Чат: https://t.iss.one/htmlshitchat

№5001017849, https://www.gosuslugi.ru/snet/679b74f8dad2d930d2eaa978
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня

Итак, сегодня в уютный канальчик™️ с ноги залетает уже всем известный Джей c кое-чем насколько потрясающим, настолько же и забытым.

И это API document.getAnimations(), позволяющий не только получить список всех CSS-анимаций, но и, внимание, выставить промис и дождаться их выполнения! 🤯

const animations = document.getAnimations()
.map(a => a.finished)
await Promise.all(animations)


Сразу кодпен: https://codepen.io/alinaki/pen/rNoEOwX

*с некоторых пор я начал форкать пены, потому что пропадают иной раз

Теперь о применимости.

Я нынче разработчик корпоративный, потому мне интересно это, например, с позиции совершения какой-нибудь операции по скрытию уведомления-тоста. Во время онбординга, например.

Ну а разработчикам промо-сайтов важность синхронизации действий и анимаций объяснять не надо.

Отличный пример забытых технологий 🙂

Не, ну серьёзно, оно с 75 Firefox доступно, как я мог его проглядеть?

А я знаю, как. Я же писал уже, что PR-служба Chrome работает прекрасно только в том случае, когда что-то появилось там первым...

#css #js #animations #promise #бородач
15👍2🤩1
#новость дня

Итак, мы писали Джаваскрипт в браузере, в консоли, на серверах, на микроконтроллерах, в играх, в кофеварках, в аудиоплеерах, телевизорах, в макросах офисных пакетов, в NoSQL базах данных...

Но до сих пор не писали его в хранимых процедурах MySQL!

Встречайте: JavaScript Stored Programs in MySQL. И соответствующий пост в блоге Oracle: https://blogs.oracle.com/mysql/post/introducing-javascript-support-in-mysql

Зачем? Ну для разных целей:
1. Извлечение данных, очевидно
2. Форматирование
3. Примерный поиск
4. Валидация данных
5. Собственные алгоритмы сжатия, сериализации и десериализации данных

Пример:


CREATE FUNCTION gcd_js (a INT, b INT) RETURNS INT
LANGUAGE JAVASCRIPT AS $$

let [x, y] = [Math.abs(a), Math.abs(b)];
while(y) [x, y] = [y, x % y];
return x;

$$;

Работает всё, ожидаемо, на GraalVM. Почему ожидаемо? Ну потому что Oracle и Java/JVM :)

Что, котаны, пишем стартап на MySQL? 😬

#mysql #sql #js #бородач
🤩11🤡5👍31
Media is too big
VIEW IN TELEGRAM
#заметка дня

Тут в нашем чатике aka @htmlshitchat человек задал вопрос: «Как заставить событие произойти только после долгого нажатия на кнопку?»

И, вроде, очевидный ответ: ставь таймаут да отменяй его:

Осторожно, псевдокод jQuery


let r = null;

$button.on("mousedown", function(e) {
e.preventDefault();
e.stopPropagation();
r = window.setTimeout(function() {
$button.html('Clicked');
}, 3000);
});

$button.on("mouseup", function() {
$button.html('Hold me');
window.clearTimeout(r);
});


Но это было бы скучно и недостаточно для поста, не правда ли?

И тут я вспомнил, что в 2017 году уже делал нечто подобное. Тогда не обошлось без погружения в Three.js и математику шестиугольников. Я об этом уже рассказывал: https://t.iss.one/htmlshit/2639

Немного покопавшись в вебархиве, я нашёл тот проект. Итак, что же мы делали?

А вот на видео видно.

Анимация была оформлена на Tween.js, который всё ещё очень и очень популярен. Правда, название их последнего релиза ну прям удручает. End of the end — серьёзно?

С 2017 года API их, конечно же, поменялся. Мне хотелось одновременно и последний вариант API вам показать, и сетку заставить работать... как хорошо, что мы в вебе, где можно вообще всё!

Итак, кодпен: https://codepen.io/alinaki/pen/KwPwVPr?editors=1100

Весь современный код упихан в секцию с HTML, в script type="module", где импортированы нужные модули и константы из ESM-версии Tween.js, он же является нашим скоупом.

Это вообще очень удобный паттерн чтобы быстро накидать пример без бандлинга.

По зажатию кнопки мыши запускаем анимацию forward, по отпусканию кнопки — запускаем reverse. Из breaking changes — раньше можно было просто вызвать start(), а теперь нужно вызывать startFromCurrentValues(), иначе красоты не получится.


function forward() {
tween.stop().to({
value: 2000
}, 3000).startFromCurrentValues();
}

function reverse() {
tween.stop().to({
value: 1000
}, 3000).startFromCurrentValues();
}


Достаточно просто и эффектно.

#js #animation #tween
👍172🤡2
#новость дня

Котаны, языку JavaScript сегодня исполнилось 29 лет!

4 декабря 1995 года после фееричных 10 дней разработки Брендан Эйх представил компании Netscape язык LiveScript, предназначавшийся для встраивания в их всё ещё свежий и самый популярный в мире браузер.

Но яйцеголовые маркетологи были уже тогда, потому язык быстренько обозвали JavaScript и выкинули на рынок как есть. Да, история немного сложнее и они реально собирались создать упрощённый вариант Java и JVM, но уж получилось как получилось.

Продавать это всё равно решили как простое решение для добавления интерактива на веб-страницы используя ваши существующие ресурсы в виде программистов на Java.


В итоге, JavaScript прошёл все круги издевательств, особенно от Microsoft. Был стандартизирован как EcmaScript, а году так в 2008 его даже называли СНЯП: Самый Недооценённый Язык Программирования.

Ну в 2024 году мы с вами точно можем сказать, что если кого и недооценили — то это точно не JS.

В общем, дальнейшего джаваскрипту развития, котаны! Всё только начинается.

#js #jscript #ecmascript #бородач
👍187🤩2
#такое дня

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

Да, вы не ослышались. В итоге, на сообщение в 10000 символов задержка может составить две-три секунды.

Не надо так, котаны.

Ссылка на тред: тут. В треде народ развлекается разным профайлингом, очень интересно: React Scan, Chrome Profile, немного реверс-инжиниринга...

Как же решать такую задачу? Ну, например, debounce или throttle, зависит от условий. Или предсказание по первому символу.

#js #react
🤡143👍2
#инструмент дня

Примерно пять раз в секунду где-то в мире очередному разработчику приходит в голову идея: «А что если я этот виджет сделаю независимо от основного приложения, на каком-нибудь миниатюрном фреймворке, чтобы было модно, молодежно переносимо?»

Когда такая идея приходила мне, я взял Preact, а потом Van. А тут недавно на собеседовании кандидат рассказал, что тоже сталкивался с подобной задачей и решил её через µhtml.

Микрохатээмэль

Сразу ссылка: https://github.com/WebReflection/uhtml

JSX там нет, вся работа через шаблонные литералы. Что, впрочем, выглядит вполне нормально:

import { render, html, signal, detach } from 'uhtml/preactive';

const count = signal(0);

render(document.body, () => html`
<button onclick=${() => { count.value++ }}>
Clicks: ${count.value}
</button>
`);

// stop reacting to signals in the future
setTimeout(() => {
detach(document.body);
}, 10000);


И да, ваши глаза вас не обманывают: сигналы! И SSR.

В общем, глаза кандидата так светились, что мне тоже надо будет попробовать.

А ваши варианты, котаны?

#uhtml #js #framework
👍72
This media is not supported in your browser
VIEW IN TELEGRAM
#проект дня

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

Ну что же, я сделал!

Идея показалась интересной, особенно с перспективой в будущем генерировать глитч-видео на основе ритма. Но реализация оказалась не такой простой, как я думал.

Основные этапы разработки:

1. Загрузка аудиофайлов — обработка mp3-файлов и их воспроизведение в браузере.
2. Извлечение обложки — получаем картинку из метаданных трека.
3. Анализ аудиопотока — детектируем ритм и биты разными методами.
4. Генерация глитч-эффектов — синхронизируем глитчи с музыкой.

Для реализации я использовал:
- powerglitch — библиотека для создания глитч-эффектов.
- WebAudio API — анализ аудиопотока в браузере.
- music-metadata — для извлечения метаданных, в том числе обложек, из mp3.

Проблема с обложкой

На этапе парсинга метаданных и отображения обложки неожиданно возникла проблема: maximum stack size exceeded.

Всё оказалось просто: обложки были тупо слишком большими, поэтому я выходил за пределы максимального размера блока. А он всего 64 килобайта, которых хватит всем.

Нужно было обрабатывать данные поблочно.

Решилось всё использованием библиотеки uint8array-extras, хотя, если честно, решение лежало на поверхности. С другой стороны, есть нюанс с Юникодом.

И, к сожалению, библиотека powerglitch просто не позволяет менять настройки глитча на лету. Но она оказалась достаточно производительной, чтобы просто пересоздавать.

Методы детектирования ритма

Я добавил несколько способов анализа:
- Spectral Flux — анализ изменений спектральной энергии.
- Zero Crossing Rate — количество пересечений нуля в сигнале.
- Beat Tracking — поиск ударов в аудиопотоке.
- Energy Detection — резкие скачки громкости.
- Peak Detection — анализ пиков сигнала.

Сейчас плеер работает, но хочется добавить больше визуальных эффектов и попробовать другие алгоритмы анализа. Впрочем, на драмэндбассе любой сравнительно хорошо работает. Хотя надо бы ещё ручки покрутить.

Жаль, браузеры не могут записывать видео с самих себя... Но это мы решим :)

Ах, да. Посмотреть можно вот тут: https://bekharsky.github.io/GlitchBeat/

И репка: https://github.com/bekharsky/glitchbeat

Пощёлкайте разные виды определения ритма. Там очень далеко от идеала, но иногда получается прям хорошо.

#js #audio #glitch #effect #music
👍194🤩1
#заметка дня

Как мы все знаем, в JavaScript есть две формы «пустоты»: undefined и null.

Но почти весь современный фронтенд давно выбрал сторону.

null — это ошибка на миллиард долларов, о которой пожалел даже его создатель, Тони Хоар. Он добавляет путаницу, ломает API и заставляет писать лишние проверки.

Почему null — плохая идея:
Разные API возвращают то null, то undefined, то оба.

Это неясно, это ошибки.

TypeScript-гайд от Microsoft прямо говорит: используйте undefined, избегайте null.

В TSLint null запрещён по умолчанию (`no-null-keyword`).

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

В крупных экосистемах, например, как у Prisma, null создаёт баги и недопонимание в API (issue #572)

undefined — поведение по умолчанию в JS для необъявленных свойств и пустых объектов.

undefined выигрывает даже в JSON. Когда ты сериализуешь данные:

null остаётся в объекте:


{ "a": null }


а undefined просто исчезает:


{ "a": undefined } → { }


В реальных системах это даёт выигрыш в размере и читаемости. Пример из продакшена: объект с миллионом null весил 13.9 MB, а с undefined — всего 21 байт. И если ты работаешь с Node.js и хорошо контролируешь свои API — undefined тебе только на руку.

Да, из-за того, что множество систем до сих пор оперирует null, и даже DOM API возвратит null при отсутствии элемента (ноды), выбор становится не настолько простым. К счастью, мы можем использовать optional chaining (?.) и nullish coalescing (??) чтобы снизить вероятность конфуза.

Кстати, даже столь любимый мной Effector ещё не так давно пропагандировал null для пустых сторов, но с недавнего времени разрешил undefined (в своей манере, там сложная концепция).

Итак, null — это рудимент. Он создаёт больше проблем, чем решает. undefined уже делает всё, что нужно — чище, предсказуемей и легче.

Пора выбрать сторону 🦄

P. S. человек, который заставил меня принять сторону сейчас, наверное, сидит и хихикает. Но в целом, единственное, что у меня есть в защиту null — это наш бакенд на PHP и MySQL 🤷

#js #ts #eslint #null
👍29👎9🤩5
#заметка дня

Вчерашний день начался с лёгкой тряски из-за неспособности некоторых разработчиков правильно обрабатывать такую простую вещь, как аналитику ссылок:

Каждый веб-разработчик, который блокирует открытие ссылки в новой вкладке по нажатию Ctrl/Cmd или средней кнопкой мышки — мой личный враг. Этому нет ни единого разумного объяснения.


Собственно, код вы видите на иллюстрации. Прекрасно видно, что поведение по-умолчанию уничтожено, взамен ничего не предложено. При этом я всё ещё могу кликнуть по ссылке правой кнопкой мыши и выбрать "Открыть в новой вкладке".

Спасибо хотя бы на этом.

Итак, но намерения-то ясны: хотят получить аналитику. HSCO — это неймспейс компании, а DataLayer это — ну кто бы мог подумать — буквально Google Analytics gtag.

Впрочем, эту же аналитику они теряют, если я кликаю правой кнопкой мыши.

Чем же заменить подобное? Ну, во-первых, а надо ли вам это делать? Чем проход по ссылке и событие "select item" там отличается от непосредственного клика? Ведь чтение referrer никто не отменял. И, очевидно, для SPA и островных приложений это вообще проблемой не является.

Но если очень надо собирать данные именно в момент клика куда-то на странице, можно воспользоваться navigator.sendBeacon().

Да, нужно будет настроить Measurement API в Google Analytics, но в итоге всё сведётся к простой функции:


function trackEventWithBeacon(eventName, params = {}) {
const measurementId = 'G-XXXXXXX'; // ← замени на свой GA4 ID
const apiSecret = 'YOUR_API_SECRET'; // ← замени на свой API Secret
const clientId = getClientId(); // читаем из _ga cookie

const payload = {
client_id: clientId,
events: [{
name: eventName,
params
}]
};

const url = `https://www.google-analytics.com/mp/collect?measurement_id=${measurementId}&api_secret=${apiSecret}`;
const blob = new Blob([JSON.stringify(payload)], { type: 'application/json' });

navigator.sendBeacon(url, blob);
}


Собрать данные можно в момент клика или по наведению мыши на ссылку, чтобы минимизировать потери во время чтения атрибутов, а уже отправить их — как в обработчике клика, так и по событию visibilitychange документа.

А ещё вы почти всегда можете отправить дополнительные параметры запроса и считать их по факту. Таким образом, не потеряли бы ни клик, ни открытие в новой вкладке, ни шаринг.

В общем, вряд ли был какой-то злой умысел, скорее, банальный skill issue. Но честное слово, не надо так. Не ломайте дефолтное поведение элементов, пожалуйста.

#analytics #js
👍245
#игра дня

Давненько не было чего-то необычного.

Впрочем, если вы не фанат Dwarf Fortress, конечно.

Untrusted — это игра, в которой вам предлагают не просто пройти уровень, а сначала починить его. Или, если точнее, подправить JavaScript-код, который за него отвечает. Персонаж — профессор Эвал — застрял в виртуальной реальности, и единственный способ выбраться оттуда — лезть в исходники и аккуратно, а иногда и не очень, их переписывать.

Каждый уровень — это кусок JS-кода, который можно и нужно менять: отключить ловушку, переписать поведение врагов, добавить себе проход в стене — пожалуйста. Главное — чтобы заработало.

Игру сложно назвать обучающей, но если вы когда-то писали на JavaScript и у вас осталась эта мышечная память for (var i = 0; i < ...), будет ощущение, что вы просто продолжаете работу, только теперь в компании ASCII-графики и странного профессора.

🎮 https://untrustedgame.com/ 📂 https://github.com/AlexNisnevich/untrusted

#game #js
🤩137