优化 JavaScript - 密码生成器(速度提高 2.15 倍)

我在 Github explore 上搜索时发现了一个密码生成器(omgopass)(https://github.com/omgovich/omgopass),据说它比其他替代品要快得多。比 600 倍快password-generator(https://www.npmjs.com/package/password-generator)

这是基准测试omgopass显示:

原始 omgopass 基准

看到这个后,我记得几周前我做了一个密码生成器,并且没有执行任何基准测试,所以我决定用其他库测试我的方法。

令我惊讶的是,它表现得相当好,在相同的基准测试中获得第二名,如上所示。即使不尝试也很好。

使用我的 pass 生成器进行基准测试 ( passGenny)(https://github.com/nombrekeff/pass-genny):

通过 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

好的,我注意到的第一件事是,在 中_getCharactersForOptions,我使用数组来保存有效字符。使用扩展运算符将它们附加到combinedCaracters数组中。

这有点多余,因为我们可以一直使用字符串。连接字符串比组合数组便宜得多。

让我们看看我们可以改变什么。

首先我们需要改变存储字符的方式,我们不需要分割它们:

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

太好了,现在我们来修改_getCharactersForOptions方法:

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;
    }
}

请注意我们现在如何返回一个字符串,而不是一个数组。

让我们看看它在基准测试中的表现如何

通过一级优化的 passGenny 进行基准测试

妈的,没想到变化这么大,几乎翻了一倍。

正如您所看到的,在这种特殊情况下,字符串的性能比数组好得多。

可是等等

我想我可以进一步优化它,你可能已经注意到,使用相同的选项,结果_getCharactersForOptions总是相同的。这意味着我们不需要连接每个密码上的字符串,我们只需要在选项更改时生成它们。

我们可以通过多种方式来解决这个问题,使用记忆化(可能更好)、围绕对象创建代理或我接下来将向您展示的简单方法。

优化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以来选项是否已更改。_getCharactersForOptions

  2. 我们将最后一个组合字符存储在_combinedCharacters

  3. 我们修改_getCharactersForOptions,这样如果选项没有改变,我们返回最后生成的_combinedCharacters

  4. 我们改变password +=(password.concat()在我的测试中,它 concat 的表现比 += 更好)

就是这样,让我们看看它是如何做到的:

passGenny 的基准测试具有两个优化级别

如果你问我的话,令人印象深刻的是,我们传球的速度比吉尼快了一倍,以相当大的优势取得了第一。如果我们像omgovich那样表述它,它比密码生成器passGenny(https://www.npmjs.com/package/password-generator)快 2,444 倍

从中可以得到什么?

  • 保持简单可以等同于高性能

  • 如果不需要,不要使用数组

  • 检查是否每次都需要执行操作

  • 如果您需要性能,有时较小的事情会产生最大的差异

PD:我不是性能专家,所以我可能会错过一些重要的事情,如果我错过了某些内容或误解了结果,请告诉我。

网友反馈留言1

您还可以进行一些改进(主要针对 DX,而不是针对性能):

  • 使用 使私有成员真正成为私有成员#。

  • 使用 getter 和 setter。

  • 将静力学移至常量。

  • 的经典类过程this.generate = this.generate.bind(this);,因此人们可以在地图等内容中使用该函数而不会出现问题。

应用这些建议,代码看起来像这样(我添加了 JSDocs 以获得更好的 DX):

/**
 * @typedef PasswordGeneratorOptions
 * @property {number} [length=12]
 * @property {boolean} [lowercase=true]
 * @property {boolean} [numbers=true]
 * @property {typeof mathRandom} [randomFunction=mathRandom]
 * @property {boolean} [symbols=false]
 * @property {boolean} [uppercase=true]
 *//**
 * @param {number} min
 * @param {number} max
 */const mathRandom = (min, max) => Math.floor(Math.random() * (max - min) + min);const uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";const lowercaseChars = "abcdefghijklmnopqrstuvwxyz";const symbolsChars = "<>[]{}=?()&%$#@!¡?¿*_-.:;,";const numbersString = "0123456789";export class PasswordGeneratorFast {
    /** @type {PasswordGeneratorOptions} */
    #options = {
        length: 12,
        lowercase: true,
        numbers: true,
        randomFunction: mathRandom,
        symbols: false,
        uppercase: true
    };
    #characters = "";
    #optionsChanged = true;
    set options(options) {
        this.#optionsChanged = true;
        this.#options = {
            ...this.#options,
            ...options
        };
    }
    get options() {
        return this.#options;
    }
    get characters() {
        if (this.#optionsChanged) {
            this.#characters =
                (this.#options.lowercase ? lowercaseChars : "") +
                (this.#options.uppercase ? uppercaseChars : "") +
                (this.#options.symbols ? symbolsChars : "") +
                (this.#options.numbers ? numbersString : "");
            this.#optionsChanged = false;
        }
        return this.#characters;
    }
    /** @param {PasswordGeneratorOptions} options */
    constructor(options = {}) {
        this.options = options;
        this.generate = this.generate.bind(this);
    }
    generate() {
        const { characters } = this;
        const length = characters.length;
        let password = "";
        for (let char = 0; char < this.#options.length; char++) {
            password = password.concat(
                characters[this.#options.randomFunction(0, length)]
            );
        }
        return password;
    }}

性能方面我的可能是最差的(没有测试它,但我认为 setter/getter 的性能不如仅使用方法,我可能是错的),但除了性能之外,我们总是必须考虑 DX,并且从我的从角度来看,在处理类时,getter 和 setter 提供了更好的 DX。我个人更喜欢只使用函数,甚至不去上课。

网友反馈留言1

我的主要原因主要是用法:

import { Something } from "./Something";

console.log(Something.aValue);

// vs

import { aValue } from "./Something";

console.log(aValue);

我知道,超级利基,但是以前从类中有用的封装现在我从模块中获得:D文章来源地址https://www.toymoban.com/article/377.html

到此这篇关于优化 JavaScript - 密码生成器(速度提高 2.15 倍)的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.toymoban.com/article/377.html

如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 一个解放双手、提高工作效率的代码生成器!

    大家好,我是 Java陈序员 。 要说现在 Java 后端开发中,最火的框架肯定是 SpringBoot 。 而持久层的框架首推 MyBatis , MyBatisPlus 作为 MyBatis 的增强框架,其强大的 CURD 能力,被广大的开发者所喜爱! SpringBoot + MyBatisPlus 可以说是王炸级别的组合! 今天给大家介绍一个可以 快速生

    2024年02月05日
    浏览(6)
  • Python中的迭代器与生成器提高性能的秘密武器【第143篇—迭代器与生成器】

    Python中的迭代器与生成器提高性能的秘密武器【第143篇—迭代器与生成器】

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在Python编程中,迭代器和生成器是提高性能和减少内存消耗的重要工具。它们不仅简化了代码结构,而且在处理大型数据集时具有明显的优势

    2024年03月24日
    浏览(11)
  • Javascript——生成器(Generator)自动执行

    Generator自动化是通过Thunk函数进行实现,写这篇文章的目的是为了理解通过Thunk实现Generator函数的自动执行。 我们可以带入一个业务场景来帮助我们理解Thunk实现Generator自动执行的好处,业务场景如下: 假设小明今天干了一件事情是:         1、买菜         2、买完菜回家

    2024年03月25日
    浏览(8)
  • JavaScript 生成器函数详解:优雅处理异步任务流

    目录 1. 生成器函数的定义和使用 2. 暂停和恢复执行 3. 与其他语言特性的配合使用 Iterator Protocol 迭代器协议  解构赋值  生成器和 Promise 的组合使用          使用 Promise:         使用 async/await: 委托给另外一个Generator函数         Generators 是 JavaScript 中的一种

    2024年02月12日
    浏览(5)
  • 构建Python随机密码生成器:保障账户安全的简易工具

    构建Python随机密码生成器:保障账户安全的简易工具

    💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】 🤟 基于Web端打造的:👉轻量化工具创作平台 💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 密码安全是当前数字时代的一个重要议题。在保护个人信息和账户安全方面,安全且可靠的密码是至关重

    2024年02月03日
    浏览(8)
  • AI智能问答助手 AI智能批量文章生成器 网站优化SEO批量内容生成工具 文章生成软件

    AI智能问答助手 AI智能批量文章生成器 网站优化SEO批量内容生成工具 文章生成软件

    《AI智能问答助手》   软件基于当下热门的OpenAI的ChatGPT技术,导入问题列表就可以批量生成对应的内容,内容质量高、原创度高。适合对内容生成需求量大的场景,如网站优化、广告文案等等。。。 使用操作简单、小白也能容易上手。 更多功能/: ab18cn     OpenAI GPT是OpenA

    2024年02月08日
    浏览(14)
  • 手机通话记录生成器在线,通话记录生成器下载,通话记录生成器app

    手机通话记录生成器在线,通话记录生成器下载,通话记录生成器app

    在了解通话记录生成器app的时候,铁牛通话记录生成器是一个为用户一键自动生成通话记录的app。如何得到“铁牛通话记录生成器”?在手机上进去佰渡baidu搜嗦,铁牛通话记录生成器,这几个字就可以,其他的不用输入。或者你看这个几个字母jp155再加上一个点com,手动输入

    2024年02月08日
    浏览(39)
  • python3 生成器与生成器表达式

    在 Python3 中,生成器表达式是一种语言结构,它可以快速地创建一个可迭代对象。生成器表达式类似于列表推导式,但使用圆括号而不是方括号,并且返回的是一个生成器对象而不是一个列表。 在 Python3 中,生成器表达式有两种类型:生成器函数和生成器表达式。 生成器函

    2024年02月02日
    浏览(32)
  • 关键词生成器在线-在线免费关键词生成器

    关键词生成器在线-在线免费关键词生成器

    生成,什么是生成,生成就是根据你输入的一个生成成千上百的核心,围绕着你输入的核心词来生成的,优先生成大量用户搜索的,今天就给大家分享一款免费生成工具,生成的来源主要是用户都在搜索的词,相关搜索的

    2024年02月04日
    浏览(37)
  • ai论文生成器哪家好用?ai写作生成器免费

    ai论文生成器哪家好用?ai写作生成器免费

    AI论文生成器的好坏取决于具体的需求和场景,因此很难一概而论。以下是一些常见的AI论文生成器,供您参考: AIPaperPass:这是一款全智能自动写作平台,拥有自主模型并对外开放API接口。它可以根据用户提供的和要求,自动生成高质量的文章内容,并且支持批量写作

    2024年01月19日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包