Недавно наткнулся на занимательный merge request по замене зависимости isNumber. Удивительно было в целом осознавать, что как такого универсального метода по определению числа в переменной нет в базовой концепции JavaScript. И данная проблема породила npm-репозиторий isNumber c почти 72 миллионами еженедельных скачиваний на сентябрь 2024 года. Но стоит ли в очередной раз использовать мизерную зависимость в своём проекте? Предлагаю взглянуть на решение, представленное в ранее сказанном mr-е.
Разбор решения
Концепция isNumber проста: функция, в аргументе которого должна быть определяемая переменная, должна вывести нам true или false; true если да, false если нет. Всё просто!
Вот так выглядит данная функция в реализации:
const isNumber = (v) => (typeof v === "number" && v - v === 0) || (typeof v === "string" && Number.isFinite(+v) && v.trim() !== "");Выглядит тяжко, не так ли? Давайте разберём каждый участок кода и выясним, решает ли эта функция нашу задачу.
Функция принимает аргумент v(variable), с которым и предстоит работать.
Суть работы заключается по-большей части в том, чтобы отловить любую выдачу типа number в данной переменной.
Первая часть проверяет напрямую числовое значение(даже тот же Infinite)
- С - typeof v === "number"всё вполне ясно. Прямая проверка типа
- v - v === 0будет возвращать true в случае с числом, так как если бы мы работали, например, со строкой, то такое выражение возвращало бы- NaN. Но в случае с массивами это бы не прокатило и данное выражение выдало бы нам тоже 0. Двигаемся дальше.
Вторая часть проверяет строки, которые могут быть преобразованы в числа.
- typeof v === "string"проверяет, является ли переменная- vстрокой.
- Number.isFinite(+v)— здесь строка- vприводится к числу с помощью унарного оператора- +. Если после преобразования строка является конечным числом (то есть не- NaN, не- Infinite), то- Number.isFiniteвернёт- true. Это важно для того, чтобы отсеивать строки, которые не могут быть корректно преобразованы в числа (например,- "abc"или пустые строки).
Унарный, то есть применённый к одному значению,
+ничего не делает с числовыми значениями. Но если переменная не число, унарный плюс преобразует его в число.
- v.trim() !== ""— эта проверка удаляет пробелы в начале и в конце строки и проверяет, что строка не пуста. Это нужно для того, чтобы отсеивать строки, состоящие только из пробелов, которые могут быть преобразованы в- 0, но на практике не являются корректными представлениями чисел.
Общий взгляд
Подытоживая мы видим две части, которые выполняют следующие задачи:
- Проверка чисел ( - typeof v === "number" && v - v === 0): Важно не только проверять тип, но и исключать- NaN, который имеет тип- "number", но фактически не является числом. Проверка через- v - v === 0— это эффективный способ исключить- NaN, так как для всех других чисел разница числа с самим собой всегда равна нулю.
- Проверка строк ( - typeof v === "string" && Number.isFinite(+v) && v.trim() !== ""): Строки, которые можно преобразовать в числа, часто встречаются в веб-разработке, особенно при работе с формами или API, где данные передаются в виде строк. Важно правильно обработать строки, которые могут быть преобразованы в числа, и отсеять пустые строки или строки, состоящие только из пробелов. Использование- Number.isFiniteпозволяет проверить, является ли преобразованное значение конечным числом.
Так что же там с репозиторием?
Пакет to-regex-range, речь о котором шла в начале статьи имеет на момент создания merge request-а 43 миллиона скачиваний, а изначальный размер пакета составляет 33Kb. Важно учесть, что основная логика данного пакета состоит из одного среднего по размерам .js файла с парой зависимостей.
После замены пакета isNumber на собственное решение из зависимостей обнаружили, что to-regex-range стал легче на 10Kb. Но эта цифра кажется не играющей, но факт остаётся фактом, что по-итогу небольшое изменение привело к сокращению еженедельного трафика скачивания на 440 гигабайт, сократив с 1.5ТB до 1.0TB. Это уже звучит действительно внушительно.
Package size report
===================
Package info for "to-regex-range@5.0.1": 33 kB
  Released: 2019-04-07 06:04:37.03 +0000 UTC (277w2d ago)
  Downloads last week: 43,837,006
  Estimated traffic last week: 1.5 TB
Removed dependencies:
  - is-number@7.0.0: 10 kB (30.06%)
    Downloads last week: 43,875,245
    Downloads last week from "to-regex-range@5.0.1": 43,837,006 (99.91%)
    Estimated traffic last week: 440 GB
    Estimated traffic from "to-regex-range@5.0.1": 440 GB (99.91%)
Estimated package size: 33 kB → 23 kB (69.94%)
Estimated traffic over a week: 1.5 TB → 1.0 TB (440 GB saved)Комментарии (41)
 - Andchir17.09.2024 20:15+7- После замены пакета - isNumberна собственное решение- На самом деле там нет собственного решения. Просто взяли код функции из пакета и сделали из него однострочник. 
 - ganqqwerty17.09.2024 20:15+7- Чего-то я не понял. Чей траффик уменьшился? Как инлайн функции связан с траффиком?  - Roman2dot017.09.2024 20:15+1- Связан так, что некоторые выкачивают десятки гигабайт заисимостей ежедневно при сборке, т.к не ставят кэш сервер.  - Andchir17.09.2024 20:15- Тут нужно уточнить, что кэширующий сервер нужен только для очень большой команды разработчиков. Для одного разработчика он не нужен (у npm есть свой кэш).  - VADemon17.09.2024 20:15- В стародавние времена люди подключали вундер-проги сжатия HTTP-трафика, потому что протокол позволял. Прокси сами, на своих сетях устанавливали провайдеры, кэшируя запросы в пределах своих сетей. Не без причины провайдеры-же организовывали сервисы в интранете, экономя трафик и создавая внутригородской движ. Разумеется, популярностью пользовался Bittorrent внутри ISP. - Это потом интернет стал быстрее и дешевле, государства наглее, а правоторговцы ярее. И лавочка прикрылась, а HTTP покрылся TLS. - Я бы не отказался от кэша Steam (программа есть), дистрибутивов Linux (по HTTP) и других. Да, не всем поможет (у меня последняя миля - VDSL). Банальнейший пример: обновлять три системы на дистрибутиве с rolling release. Большая часть времени уходит на скачивание. Так что может и сам себе прокси поставлю. 
 
 
 
 - VADemon17.09.2024 20:15- Проверка через v - v === 0 — это эффективный способ исключить NaN, так как для всех других чисел разница числа с самим собой всегда равна нулю. - Нет, здесь также бесконечности отсекаются (зачем-то). 
 
           
 
Rorg
Где именно в начале статьи идет речь о пакете
to-regex-range? (Если конечно не переходить по ссылке на оригинальный mr)