Рубрики
Без рубрики

Давайте оптимизируем JavaScript – генератор паролей (в 2,15 раза быстрее)

Я искал через GitHub Explore, когда я нашел генератор паролей (OMGOPASS), что якобы … Tagged с JavaScript, Node, Performance, Programming.

Я искал сквозь Github, когда я нашел генератор пароля ( Omgopass ), что предположительно было намного быстрее, что другие альтернативы. В 600 раз быстрее, чем Пароль-генератор Анкет

Это ориентир Омгопассы:

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

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

Конфликт с моим генератором проходов (Passgenny):

Соображения

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

Кроме того, функции варьируются от одной библиотеки к другой, одну – читаемые, а одно нет. Некоторые используют крипто для случайных, некоторые нет.

С этим говорим,

Давайте сделаем Passgenny быстрее

Я решил пойти пойти и попробовать оптимизировать его, давайте посмотрим оригинальный код:

class PasswordGenerator {
    static upperCaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
    static lowerCaseChars = 'abcdefghijklmnopqrstuvwxyz'.split('');
    static symbolsChars = '<>[]{}=?()&%$#@!¡?¿*_-.:;,'.split('');
    static numbersString = '0123456789'.split('');

    constructor(options = {}) {
        this.options = {
            uppercase: true,
            lowercase: true,
            symbols: false,
            numbers: true,
            readable: false,
            length: 12,
            ...options,
        };
    }

    updateOptions(newOptions = {}) {
        this.options = {
            ...this.options,
            ...newOptions,
        };
    }

    random(min = 0, max = 10) {
        return Math.floor(
            Math.random() * (max - min) + min
        );
    }

    _getCharactersForOptions() {
        const combinedCaracters = [];

        if (this.options.lowercase)
            combinedCaracters.push(...PasswordGenerator.lowerCaseChars);
        if (this.options.uppercase)
            combinedCaracters.push(...PasswordGenerator.upperCaseChars);
        if (this.options.symbols)
            combinedCaracters.push(...PasswordGenerator.symbolsChars);
        if (this.options.numbers)
            combinedCaracters.push(...PasswordGenerator.numbersString);

        return combinedCaracters;
    }

    generate() {
        let combinedCaracters = this._getCharactersForOptions();
        let password = '';

        for (let c = 0; c < this.options.length; c++) {
            password += combinedCaracters[this.random(0, combinedCaracters.length)];
        }

        return password;
    }
}

То, что делает этот класс, из набора вариантов, он будет генерировать пароли. Это делает это путем объединения всех разрешенных символов (по параметрам) в один массив, затем мы переиграем длину пароля (определено параметрами) и получите случайную символ из этого массива.

Достаточно простого правильно? Теперь я думаю, что мы могли бы оптимизировать это совсем немного, будем ли мы?

Оптимизация 1.

Хорошо, первое, что я заметил, в _getCharacterForoptions. Я использую массивы, чтобы держать действительные символы. Использование оператора распространения для добавления их в Комбинированные скрепки множество.

Это довольно избыточно, так как мы могли бы использовать строку. И объединение строки намного дешевле, что объединяет массивы.

Давайте посмотрим, что мы могли бы изменить.

Сначала нам нужно изменить, как мы храним персонажей, нам не нужно их разбивать:

class PasswordGenerator {
    static upperCaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    static lowerCaseChars = 'abcdefghijklmnopqrstuvwxyz';
    static symbolsChars = '<>[]{}=?()&%$#@!¡?¿*_-.:;,';
    static numbersString = '0123456789';
    // ... more code
}

Отлично, теперь давайте изменим _getCharacterForoptions. Метод:

class PasswordGenerator {
    _getCharactersForOptions() {
        let combinedCaracters = '';

        if (this.options.lowercase)
            combinedCaracters += PasswordGeneratorFast1.lowerCaseChars;
        if (this.options.uppercase)
            combinedCaracters += PasswordGeneratorFast1.upperCaseChars;
        if (this.options.symbols)
            combinedCaracters += PasswordGeneratorFast1.symbolsChars;
        if (this.options.numbers)
            combinedCaracters += PasswordGeneratorFast1.numbersString;

        return combinedCaracters;
    }
}

Обратите внимание, как мы теперь возвращаем строку вместо массива.

Давайте посмотрим, как это делает в ориентире

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

Как видите, в этом конкретном случае строки работают намного лучше, чем массивы.

НО ЖДАТЬ

Я думаю, что могу оптимизировать это еще больше, вы могли бы заметить, что результат _getCharacterForoptions всегда будет одинаковым с одинаковыми вариантами. Это означает, что нам не нужно объединять строку на каждом пароле, нам нужно только генерировать их, если параметры меняются.

Мы могли бы приблизиться к этому пару способов, используя мемузаризацию (возможно, лучше), создавая прокси вокруг объекта или простой подход, который я покажу вам дальше.

Оптимизация 2.

То, что я сделаю, сделайте варианты частным и заставить людей изменить варианты, используя UpdateOptions метод. Это позволит мне отметить, если варианты изменились.

Давайте посмотрим полный пример, и я сломаю его потом:

class PasswordGeneratorFast2 {
    static upperCaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    static lowerCaseChars = 'abcdefghijklmnopqrstuvwxyz';
    static symbolsChars = '<>[]{}=?()&%$#@!¡?¿*_-.:;,';
    static numbersString = '0123456789';

    constructor(options = {}, randomFn) {
        this._options = {
            uppercase: true,
            lowercase: true,
            symbols: false,
            numbers: true,
            readable: false,
            length: 12,
            ...options,
        };
        this._random = randomFn || mathRandom;
        this._combinedCharacters = '';
        this._optionsChanged = true;
        this._getCharactersForOptions();
    }

    updateOptions(newOptions = {}) {
        this._options = {
            ...this._options,
            ...newOptions,
        };
        this._optionsChanged = true;
    }

    generate() {
        const combinedCaracters = this._getCharactersForOptions();
        const length = combinedCaracters.length;
        let password = '';

        for (let c = 0; c < this._options.length; c++) {
            password = password.concat(combinedCaracters[this._random(0, length)]);
        }

        return password;
    }

    _getCharactersForOptions() {
        // If options have not changed, we can return the previoulsy combined characters
        if (!this._optionsChanged) return this._combinedCharacters;

        let combinedCaracters = '';

        if (this._options.lowercase)
            combinedCaracters += PasswordGeneratorFast1.lowerCaseChars;
        if (this._options.uppercase)
            combinedCaracters += PasswordGeneratorFast1.upperCaseChars;
        if (this._options.symbols)
            combinedCaracters += PasswordGeneratorFast1.symbolsChars;
        if (this._options.numbers)
            combinedCaracters += PasswordGeneratorFast1.numbersString;

        // Update and mark options as not changed
        this._combinedCharacters = combinedCaracters;
        this._optionsChanged = false;

        return this._combinedCharacters;
    }
}
  1. Мы добавляем _Optionschanged указывает, изменились ли варианты с прошлого года _getCharacterForoptions назывался.
  2. Мы храним последний комбинированный персонаж в _combiedCharacters
  3. Модифицируем _getCharacterForoptions Так что, если варианты не изменились, мы возвращаем последнюю сгенерированную _combiedCharacters
  4. Мы меняем пароль += с password.concat () ( в моих тестах, он выполнил лучше, что += )

Вот и все, давайте посмотрим, как это сделал:

Впечатляюще, если вы спросите меня, мы сделали Passgenny Более того, что в два раза быстрее, забивая сначала довольно немного полем. Если мы выразим это как Omgovich сделал, Passgenny 2,444 раза быстрее, чем генератор паролей

Что брать от этого?

  • Сохранение его просто может приравнивать к исполнению
  • Не используйте массивы, если вам не нужно к
  • Проверьте, необходимо ли выполнять операции каждый раз
  • Если вам нужна производительность, иногда меньшие вещи имеют наибольшую разницу

ПД: Я не эксперт по производительности, поэтому я мог бы упустить какую -то важную вещь, пожалуйста, дайте мне знать, если я что -то пропустил, или я неверно истолковал результаты.

Хорошего дня!

Оригинал: “https://dev.to/nombrekeff/i-created-one-of-the-fastests-node-js-password-generators-without-knowing-16ll”