Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
83 - Telegram Web
Telegram Web
Друзья, поздравляю вас с Новым Годом! 🎄
У меня, как всегда, много планов и целей на этот год и очень скоро я сделаю очень важный для меня анонс. И пусть в новом году у всех нас все наши планы реализуются 🚀
Привет! Исследую одну, как мне кажется, интересную тему - определение неиспользуемых ветвей в больших объектах. Это может пригодиться, например, для анализа стейта вашего приложения с целью определить какая часть стейта является избыточной для вашего приложения, чтобы не присылать ее на клиент.
Я вижу здесь два варианта реализации: статический анализ и анализ в рантайме.
Хочу узнать что думаете и может встречали какие-то готовые решения ☺️
PS: реализовал свое решение, чуть позже расскажу
Немного подбробнее раскрою тему, которую начал выше.
Понять какие части объекта используются, а какие нет, надажнее всего через рантайм. Статический анализ не всегда помогает:
- код можно написать так, что его довольно сложно будет проанализировать статически
- не поможет в кейсах, когда обращение к свойствам в коде есть, но фактически этот код мертвый и до него дело никогда не доходит (ранее писал большой пост про DCE)

Итого, искать неиспользуемые куски объекта лучше в рантайме. В плане реализации, нужно перехватывать все попытки обратиться к любым свойствам объекта, даже к тем свойствам, которых еще нет. При попытке обратиться к свойству - фиксруем эту попытку и в нужный момент извлекаем инфрмацию о usage coverage (какие ветки используются, а какие нет).
Для этого можно использовать Proxy, что я собственно и сделал и запилил для этих целей библиотечку Gettie.
При помощи Gettie можно обернуть любой объект и следить за попытками доступа с его свойствам (без ограничения глубины).
Почитайте описание, посмотрите демку, попробуйте сами и поделитесь мыслями/идеями ☺️
Смысл демки в том, в у каждой todo в стейте приложения есть два заведемо неиспользуемых поля: createdTS и editedTS
Создавая/редактируя todo-шки, нажимайте на Refresh и смотрите как растет количество неиспользуемых веток в стейте.
Статистику можно собирать двумя путями:

1) Оборачивать стейт в рамках А/Б тестирования, например, собрать статистику только с 1% пользователей
Более правдивые результаты. И чем на больший % раскатываем - тем более правдивые результаты получаем.
Минус такого подхода - импакт по производительности клиента из-за постоянных оберток (зависит от размера стейта и частоты обращений к нему)

2) Собирать статистику во время e2e-тестов
Менее правдивые результаты, т.к. e2e-тесты лишь эмулируют поведение пользователя
🎉 Замержили мой PR в вебпак, который добавляет возможность очищать содержимое выходной директории перед сборкой:
{ output: { clean: true } }
Эдакая замена WebpackCleanPlugin
А еще, я ищу JS-разработчиков, прямо в мою команду инфраструктуры фронта 🚀
Если для вас это актуально, то присылайте резюме в личку ☺️
https://yandex.ru/jobs/vacancies/dev/front_develop_market/
https://yandex.ru/jobs/vacancies/dev/nodejs_market/
Привет! Небольшая заметка о том, как я затаскивал поддержку больших статов в генерируемые Статоскопом HTML-отчеты.
Как мы с вами уже знаем, у JS-движков есть ограничение на максимальный размер строки (например 512мб для V8)
Это значит, что при попытке получить строку большего размера, мы получим ошибку RangeError: Invalid string length
Очевидно, что для статов размером больше 512mb тот же JSON.parse работать не будет, но как раз JSON.parse нам и нужен.
Обойти ограничение можно при помощи поточного JSON-парсера. Такому парсеру нужен источник строки, который будет отдавать ее не целиком, а кусочками (например по 64кb). По мере того, как парсер получает кусочки, он пытается их распарсить - превратить в объект. Очевидно, что этот объект растет по мере парсинга. Смысл в том, что мы не обрабатываем большие строки, а следовательно, у нас не возникает исключения RangeError, а сам объект путь себе растет пока хватает оперативной памяти.
Ну хорошо, делаю первый подход - взял поточный парсер от @rdvornov, формирую HTML и инъекчу в него код вроде такого:

const chunks = [
сюда вставляю большой JSON порубленный на строки по 64kb
];
const data = await jsonExt.parseChunked(() => chunks);
Statoscope(data);


Запускаю - не работает, браузер просто зависает 🤔
Методом проб и ошибок выяснил, что бразуер просто не переваривает такой большой тег скрипт (несколько сот мегабайт). Никакой особо полезной информации я по этому ограничению не нашел, но стало ясно, что теперь я воткнулся в проблему лимитов самого браузера. Стал думать что здесь можно сделать. Пришла идея попилить на куски не только JSON, но и теги script:


<script>
chunks.push(КУСОК_JSON)
</script>
<script>
chunks.push(СЛЕДУЮЩИЙ_КУСОК_JSON)
</script>

..... здесь еще много подобных тегов script

<script>
const data = await jsonExt.parseChunked(() => chunks);
Statoscope(data);
</script>


Запустил, заработало! Теперь я смог обойти и ограничение на JSON.parse и ограничение браузера на размер тега script.
Учитывая то, что загружать в отчет можно сразу несколько файлов со статами, например, для сравнения сборок, предусмотрел пуш чанка по идентификатору стата:


<script>
api.pushChunk("stat1.json", КУСОК_JSON)
</script>

<script>
api.pushChunk("stat2.json", КУСОК_JSON)
</script>

<script>
api.pushChunk("stat1.json", КУСОК_JSON)
</script>


Таким образом даже не важен порядок, в котором статы сбрасываются в отчет.

Прошло какое-то время и @rdvornov задал интересный вопрос: "Слушай, а почему бы не использовать теги script не как скрипт, а как текст, тогда можно было бы сэкономить на парсинге?"
И действительно, если сказать браузеру, что содержимое script - это не скрипт, а текст, то браузер не будет тратить время на парсинг сожержимого. А, на минуточку, 64kb x Nk тегов script - это ощутимо.

В итоге получилось что-то вроде:


<script type="text/plain" data-id="stat1.json">КУСОК_JSON</script>
<script type="text/plain" data-id="stat1.json">КУСОК_JSON</script>

......

<script>
for (const element of document.querySelectorAll('script')) {
api.pushChunk(element.dataset.id, element.textContent);
}

const data = await jsonExt.parseChunked(() => api.getChunks());
Statoscope(data);
</script>


Там конечно чуть сложнее, полную версию изменений можно посмотреть тут

Итог этой простой манипуляции такой: время загрузки отчета со статами в 650mb сократилась с 21 секунды до 14 (профит в 33%!!!)
Мораль: почти всегда можно что-то придумать, чтобы стало лучше (даже когда кажется, что нельзя) 😉
Выпустил Statoscope 3.5
Туда вошло изменение, ускоряющее получения списка npm-пакетов и их инстансов https://github.com/smelukov/statoscope/pull/43
Это значительно уменьшило время генерирования отчета при помощи плагина.
Кстати, это первый сторонний ПР в Statoscope, который что-то улучшает 🚀

А еще, видимо что-то пошло ТАК и Statoscope начали использовать на CI, т.к. количество скачиваний резко возросло https://npm-stat.com/charts.html?package=%40statoscope%2Fui-webpack 🤘🏻
Хотя, если вы большой проект, то лучше использовать кеширующий npm-proxy, например Verdaccio
Привет!
Году в 2017 я залип на соревновании return true
Вам дается функция, нужно изучить исходный код и понять что нужно передать в функцию в качестве аргумента так, чтобы функция вернула true.
Проблема в том, что задание нужно не просто решить, а сделать это за минимальное количество символов.
Есть простые задания, а есть и зубодробительные.

Я тут раскопал свои решения из первого сезона соревнования, но с тех пор вышло много других задач.
Интересно было бы видеть тут разбор этих задачек с моими размышлениями и комментариями? В виде ссылок на статьи в телеграфе (чтобы не спойлерить тем, кто хочет решить все сам)
Хотите разбор return true?
Final Results
95%
Да
5%
Нет
https://www.joinclubhouse.com/event/M1zov8YL
Сегодня в 19:00 по МСК мы с коллегами будем болтать про сборку и отвечать на вопросы, подключайтесь ;)
Сергей Мелюков
Хотите разбор return true?
Привет! Судя по результатам опроса, почти все проголосовавшие хотят разбора.
Подготовил для вас первую статью серии
Милости прошу в комменты с вопросами/предложениями по содержимому и формату 😉
За что люблю return true, так это за то, что он побуждает вгрызаться в особенности языка и иногда заставляет читать спеку, даже если не очень-то и планировалось. Например, с удивлением обнаружил, что при постинкременте, старое значение тоже приводится к числу:
f = () => 0
f++ // NaN

Я ожидал увидеть здесь f вместо NaN, т.к. это ПОСТинкремент.
Но спека говорит примерно следующее:
...
oldValue = ToNumeric(lhs)
...
Return oldValue

В результате чего, мы вполне логично получаем NaN при попытке привести функцию к числу.
О некоторых вещах часто не задумываешься и не замечаешь, пока дело не доходит до нестандартных кейсов 🤷🏻‍♂️
Друзья, спасибо за первые 300 ⭐️ Статоскопу на Гитхабе 🎉
А давайте немного поболтаем и порешаем задачки? 🙂
Как вы уже знаете, я люблю всякие челледжи и недавно я наткнулся на такую вот задачку:


You are asked to square every digit of a number and concatenate them.
For example, if we run 9119 through the function, 811181 will come out, because 9^2 is 81 and 1^2 is 1.
Note: The function accepts an integer and returns an integer


Иначе говоря: На вход функции поступает число, каждый разряд которого нужно возвести в квадрат. Полученные квадраты разрядов нужно объединить и вернуть из функции.
На входе и на выходе должны быть именно числа (`typeof x === 'number'`). Примеры:


fn(3212) // 9414
fn(9119) //811181


Как вы решали бы эту задачу? При условии, что вам надо сразу сделать так, чтобы с точки зрения кода все было круто и эффективно.
Будет круто, если пришлете кусочки кода в какой-нибудь code pen. Или просто поделитесь мыслями.

PS: очевидно, не все так просто, иначе я бы не поднял этот вопрос 😉
Чуть позже поделюсь своими мыслями и решением 😉
PPS: Возможно такой формат окажется интересным.
2025/10/13 00:49:43
Back to Top
HTML Embed Code: