发现,node原生模块crypto生成的hash值速度js-sha256生成hash速度10倍。

891 阅读2分钟

背景:

electron开发IM,文件图片,文件上传,不断连续上传导致崩溃。 原因是内存泄漏,不断的读取本地文件,并没有及时释放掉,一口气把用户选择的文件都读取出来,进行分片上传。

我要做什么? 重构,修改它。

需要对文件进行sha256计算,生成一个唯一hash值。

在我测试不同大小的文件生成hash的速度的时候,

发现,node原生模块crypto生成的hash值速度js-sha256生成hash速度10倍。

代码如下:

环境

创建package.json, install js-sha256


npm init -y

npm install js-sha256 --save

package.json

{
  "name": "send-file-img",
  "version": "1.0.0",
  "description": "文件添加sha256指纹",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "js-sha256": "node js-sha256.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "js-sha256": "^0.9.0"
  }
}

node原生模块

index.js

const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
function sha256File(filePath, callback) {
    const sum = crypto.createHash("sha256");
    if (callback && typeof callback === "function") {
        const fileStream = fs.createReadStream(filePath);
        fileStream.on("error", (err) => {
            return callback(err, null);
        });
        fileStream.on("data", (chunk) => {
            try {
                sum.update(chunk);
            } catch (ex) {
                return callback(ex, null);
            }
        });
        fileStream.on("end", () => {
            return callback(null, sum.digest("hex"));
        });
    } else {
        sum.update(fs.readFileSync(filePath));
        return sum.digest("hex");
    }
}

// 获取文件信息
function getStatByFile(filePath) {
    return new Promise((resolve, reject) => {
        fs.stat(filePath, (err, stats) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(stats);
        });
    });
}

async function main() {
    try {
        const filePath = path.join("D:\\download", "./download.zip");
        console.time("sha256File");
        const statData = await getStatByFile(filePath);
        console.log(
            "statData.size :>> ",
            (statData.size / (1024 * 1024)).toFixed(2),
            "MB"
        );
        sha256File(filePath, (error, sum) => {
            if (error) return console.log(error);
            console.log(sum); // '345eec8796c03e90b9185e4ae3fc12c1e8ebafa540f7c7821fb5da7a54edc704'
            console.timeEnd("sha256File");
        });
    } catch (error) {
        console.error("main error", error);
    }
}
main();

node index.js

PS D:\desktop\worker\send-file-img> npm start

> send-file-img@1.0.0 start
> node index.js

statData.size :>>  885.64 MB                       5d930
ae8c98c7f0dade0c3bab37c23a83387aeece060ccdeeefb73055d93099201413
sha256File: 3.962s
PS D:\desktop\worker\send-file-img> 

js-sha256

js-sha256.js

const path = require("path");
const fs = require("fs");
const sha256 = require("js-sha256");
main();

async function main() {
    try {
        console.time("read-file-total");
        const filePath = path.join("D:\\download", "./download.zip");
        // const filePath = path.join(__dirname, "./package.json");
        // 判断 路径是否可读
        fs.accessSync(path.resolve(filePath), fs.constants.R_OK);

        const statData = await getStatByFile(filePath);
        console.log(
            "statData.size :>> ",
            (statData.size / (1024 * 1024)).toFixed(2),
            "MB"
        );
        let hash = sha256.create();
        hash = await readFileBuffer(filePath, hash);
        const fileHash = hash.hex();
        console.log("fileHash :>> ", fileHash);
        console.timeEnd("read-file-total");
    } catch (error) {
        console.error("main error :>> ", error);
    }
}


function readFileBuffer(filePath, hash) {
    return new Promise((resolve, reject) => {
        try {
            // can read
            const readStream = fs.createReadStream(filePath);

            readStream.on("data", (data) => {
                hash.update(data);
            });
            readStream.on("end", (data) => {
                resolve(hash);
            });

            readStream.on("error", (error) => {
                reject(error);
            });
        } catch (error) {
            reject(error);
        }
    });
}

// 获取文件信息
function getStatByFile(filePath) {
    return new Promise((resolve, reject) => {
        fs.stat(filePath, (err, stats) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(stats);
        });
    });
}

node js-sha256.js

PS D:\desktop\worker\send-file-img> npm run js-sha256

> send-file-img@1.0.0 js-sha256
> node js-sha256.js

statData.size :>>  885.64 MB
fileHash :>>  ae8c98c7f0dade0c3bab37c23a83387aeece060ccdeeefb73055d93099201413
read-file-total: 47.628s
PS D:\desktop\worker\send-file-img> 

完!


参考:

sha256-file
数字指纹有什么用?赶紧来了解一下
浏览器计算文件SHA256