Java, UX, HTML, CSS, WEB-design

Оптимизация длинных списков значений «да/нет» с помощью JavaScript

Краткое описание по статье Оптимизация длинных списков значений «да/нет» с помощью JavaScript

Название: Оптимизация длинных списков значений «да/нет» с помощью JavaScript . Краткое описание: [ad_1] ⭐ Леа Вер . Дата публикации: 20.02.2022 . Автор: Алишер Валеев .

Для чего создан сайт Novosti-Nedeli.ru

Данный сайт посвящен новостям мира и мира технологий . Также тут вы найдете руководства по различным девайсам.

Сколько лет сайту?

Возраст составляет 3 года

[ad_1]

  • Леа Веру

  • 0 Комментарии

Оптимизация длинных списков значений «да/нет» с помощью JavaScript

  • 8 минут чтения

  • Кодирование, JavaScript

Краткое резюме ↬

Очень часто в веб-разработке (и в программировании в целом) вам нужно хранить длинный список логических значений (да/нет, истина/ложь, проверено/не проверено… вы поняли) во что-то, что принимает только строки. Может быть, это потому, что вы хотите хранить их в localStorage или в файле cookie, или отправить их через тело HTTP-запроса. Мне нужно было сделать это бесчисленное количество раз.

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

Дальнейшее чтение на SmashingMag:

  • 7 вещей в JavaScript, которые я хотел бы знать намного раньше в своей карьере
  • Краткий обзор математики анимации с помощью JavaScript
  • 10 странностей и секретов JavaScript

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

Еще после прыжка! Продолжить чтение ниже ↓

Использование массива

У нас есть два (разумных) способа смоделировать наши данные в массиве. Один из них — хранить значения true/false, например:

[false, true, true, false, false, true, true]

Другой — хранить массив 0 и 1, например:

[0, 1, 1, 0, 0, 1, 1]

Какое бы решение мы ни выбрали, нам в конечном итоге придется преобразовать его в строку, а затем преобразовать обратно в массив при чтении. У нас есть два пути: либо со старым Array#join() (или Array#toString()) а также String#split()или с любителем JSON.stringify() а также JSON.parse().

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

Основным недостатком использования строк на основе массива является их размер в байтах. Если вы выберете числовой метод, вы будете использовать почти 2 символа на число (или, точнее, 2N − 1так как вам понадобится один разделитель на число, кроме последнего):

[0, 1, 1, 0, 0, 1, 1].toString().length // 13, for 7 values

Таким образом, для 512 номеров это будет 1023 символа или 2 КБ, поскольку JavaScript использует кодировку UTF-16. Если вы используете логический метод, это еще хуже:

[false, true, true, false, false, true, true].toString().length // 37, also for 7 values

Это примерно от 5 до 6 символов на значение, то есть от 2560 до 3072 символов для 512 чисел (что составляет от 5 до 6 КБ). JSON.stringify() даже тратит еще 2 символа в каждом случае, для открытия и закрытия скобок, но его преимущество в том, что вы возвращаете исходные типы значений с помощью JSON.parse() вместо струн.

Использование строки

Использование строки позволяет сэкономить место, поскольку не используются разделители. Например, если вы используете числовой подход и сохраняете такие строки, как ‘01001101010111’, вы, по сути, сохраняете один символ для каждого значения, что на 100% лучше, чем лучший из двух предыдущих подходов. Затем вы можете получить значения в массив, используя String#split:

'01001101010111'.split(’); // ['0','1','0','0','1','1','0','1','0','1','0','1','1','1']

Или вы можете просто перебрать строку, используя string.charAt(i) — или даже строковые индексы (string[i]), если вас не интересуют старые браузеры.

Использование битовых полей

Предыдущий метод заставил вас задуматься о двоичных числах? Это не только ты. Концепция битовых полей довольно популярна в других языках программирования, но не так популярна в JavaScript. В двух словах, битовые поля используются для упаковки большого количества логических значений в биты логического представления числа. Например, если у вас есть восемь значений (истина, ложь, ложь, истина, ложь, истина, истина, ложь), число будет 10010110 в двоичном формате; Итак, 150 в десятичном формате и 96 в шестнадцатеричном. Это 2 символа вместо 8, так что 75% сохранено. В общем случае 1 цифра в шестнадцатеричном представлении соответствует ровно 4 битам. (Это потому что 16 = 24. В общем, в base2n система, вы можете упаковать n биты в каждом base2n цифра.) Итак, нам не повезло с этими 75%; всегда так много.

Таким образом, вместо того, чтобы хранить эту строку как строку и использовать 1 символ для каждого значения, мы можем быть умнее и сначала преобразовать ее в (шестнадцатеричное) число. Как мы это делаем? Это не более чем строка кода:

parseInt('10010110', 2).toString(16); // returns '96'

И как мы читаем это обратно? Это так же просто:

parseInt('96', 16).toString(2); // returns  '10010110'

С этого момента мы можем следовать тому же процессу, что и в предыдущем методе, чтобы перебирать значения и делать с ними что-то полезное.

Можем ли мы сделать лучше?

На самом деле, мы можем! Зачем преобразовывать его в шестнадцатеричное (с основанием 16) число, в котором используются только 6 из 26 букв алфавита? То Number#toString() метод позволяет нам перейти к основанию 36 (выбрасывая RangeError для >= 37), который эффективно использует все буквы алфавита, вплоть до z! Таким образом, мы можем сжать до 6 символов для 32 значений, что означает экономию до 81,25% по сравнению с методом простой строки! И код такой же простой:

parseInt( '1001011000', 2).toString(36); // returns 'go' (instead of '258', which would be the hex version)
parseInt('go', 36).toString(2); // returns  '1001011000'

Для некоторых из вас этого будет достаточно. Но я почти слышу, как наиболее пытливые умы кричат: «Но у нас есть заглавные буквы, у нас есть другие символы, мы все еще не используем потенциал строк в полной мере!» И ты будешь прав. Есть причина, по которой каждый раз, когда вы открываете двоичный файл в текстовом редакторе, вы получаете странные символы, смешанные с цифрами, прописными буквами, строчными буквами и еще чем-то. Каждый символ в строке UTF-16 занимает 2 байта (16 бит), а это означает, что если мы используем правильный алгоритм сжатия, мы должны иметь возможность хранить в нем 16 значений да/нет (экономия 93,75% по сравнению со строковым методом). .

Проблема в том, что JavaScript не предлагает встроенного способа сделать это, поэтому код становится немного сложнее.

Упаковка 16 значений в один символ

Вы можете использовать String.fromCharCode чтобы получить отдельные символы. Он принимает числовое значение до 65 535 и возвращает символ (а для значений, превышающих это значение, возвращает пустую строку).

Итак, нам нужно разбить нашу строку на куски размером по 16 символов. Мы можем сделать это через .match(/.{1,16}/g). Подводя итог, полное решение будет выглядеть так:

function pack(/* string */ values) {
    var chunks = values.match(/.{1,16}/g), packed = ’;
    for (var i=0; i < chunks.length; i++) {
        packed += String.fromCharCode(parseInt(chunks[i], 2));
    }
    return packed;
}

function unpack(/* string */ packed) {
    var values = ’;
    for (var i=0; i < packed.length; i++) {
        values += packed.charCodeAt(i).toString(2);
    }
    return values;
}

Это было не так уж сложно, не так ли?

С помощью этих нескольких строк кода вы можете упаковать вышеупомянутые 512 значений в — барабанную дробь, пожалуйста — 32 символа (64 байта)!

Значительное улучшение по сравнению с исходными 2 КБ (с методом массива), не так ли?

Ограничения

Числа в JavaScript имеют ограничения. Для обсуждаемых здесь методов, которые включают промежуточное состояние преобразования в число, предел, по-видимому, равен1023 значения да/нет, потому что parseInt(‘1111…1111’, 2) возвращается Infinity когда количество асов больше 1023. Это ограничение не распространяется на последний метод, потому что мы конвертируем только блоки битов, а не все это. И, конечно же, это не относится к первым двум методам (массив и строка), потому что они не включают упаковку значений в целое число.

«Я думаю, вы зашли слишком далеко»

Это может быть излишним для некоторых случаев. Но это определенно пригодится, когда вы хотите хранить много логических значений в любом ограниченном пространстве, которое может хранить только строки. И никакая оптимизация не является излишней для вещей, которые часто проходят через сеть. Например, файлы cookie отправляются при каждом отдельном запросе, поэтому они должны быть как можно меньше. Другим вариантом использования могут быть многопользовательские онлайн-игры, для которых время отклика должно быть молниеносным, иначе игры не будут интересными.

И даже если такая оптимизация вам не по душе, я надеюсь, вы нашли процесс мышления и задействованный код познавательными.

Сокрушительная редакция
(аль)

Спасибо Эли Грею и Йонасу Вагнеру за советы и исправления.

Изображение на главной странице создано Ruiwen Chua.



[ad_2]
Source: https://smashingmagazine.com

Заключение

Вы ознакомились с статьей — Оптимизация длинных списков значений «да/нет» с помощью JavaScript

Пожалуйста оцените статью, и напишите комментарий.

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован.

Кнопка «Наверх»