1. 安装插件
yarn add worker-plugin
2. 配置插件
vue.config.js
const WorkerPlugin = require('worker-plugin')
configureWebpack: {
plugins: [
new WorkerPlugin()
]
}3. 编辑页面
<input
@change="onUpload"
type="file"
/>4. 编写js
methods: {
onUpload(e) {
let files = e.target.files
let file = files[0]
// 大文件size(100M)
const bigFileSize = 1024 * 1024 * 100
if (file.size > bigFileSize) {
// 创建多线程
let workers = []
let worker = new Worker('./computer.js', { type: 'module' })
worker.addEventListener('message', this.handleWorkerEvent(file))
workers.push(worker)
this.loading = true
// 切片
this.hashFile(file, workers)
}
},
hashFile(file, workers) {
let i,
bufferSize,
block,
threads,
reader,
blob,
handleHashBlock,
handleLoadBlock
bufferSize = 64 * 16 * 1024 * 10 //10M
block = {
file_size: file.size,
start: 0
}
block.end = bufferSize > file.size ? file.size : bufferSize
handleHashBlock = () => {
threads -= 1
if (threads === 0) {
if (block.end !== file.size) {
block.start += bufferSize
block.end += bufferSize
if (block.end > file.size) {
block.end = file.size
}
reader = new FileReader()
reader.onload = handleLoadBlock
blob = file.slice(block.start, block.end)
reader.readAsArrayBuffer(blob)
}
}
}
// 线程数
threads = 0
for (i = 0; i < workers.length; i += 1) {
// 监听多线程文件computer.js传过来的信息,每完成一次计算都通知列表继续文件分块
workers[i].addEventListener('message', handleHashBlock)
}
handleLoadBlock = event => {
for (i = 0; i < workers.length; i += 1) {
threads += 1
workers[i].postMessage({
message: event.target.result,
block: block
})
}
}
reader = new FileReader()
reader.onload = handleLoadBlock
blob = file.slice(block.start, block.end)
// 源文件大小和块的大小比对,取小者
block.end = bufferSize > file.size ? file.size : bufferSize
// 读取分块
reader.readAsArrayBuffer(blob)
},
handleWorkerEvent() {
return event => {
if (event.data.result) {
this.progress = 100
let self = this
setTimeout(() => {
self.loading = false
self.progress = 0
}, 500)
} else {
let progress = Math.round(
(event.data.block.end * 100) / event.data.block.file_size
)
this.progress = progress
}
}
}5. 编写 计算js
//字节转words格式(小课堂有提到该格式)
function bytesToWords(a) {
for (var b = [], c = 0, d = 0; c < a.length; c++, d += 8) {
b[d >>> 5] |= a[c] << 24 - d % 32;
}
return b
}
// words转字节
function wordsToBytes(a) {
for (var b = [], c = 0; c < a.length * 32; c += 8) {
b.push(a[c >>> 5] >>> 24 - c % 32 & 255)
}
return b
}
// 字节转十六进制字符串
function bytesToHex(a) {
for (var b = [], c = 0; c < a.length; c++) {
b.push((a[c] >>> 4).toString(16)),
b.push((a[c] & 15).toString(16));
}
return b.join("")
}
self.hash = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19];
// 在SHA256算法中,用到64个常量,这些常量是对自然数中前64个质数的立方根的小数部分取前32bit而来
var K = [0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2];
function sha256(m, H) {
var w = [], a, b, c, d, e, f, g, h, i, j, t1, t2;
for (i = 0; i < m.length; i += 16) {
//初始化工作变量
a = H[0];
b = H[1];
c = H[2];
d = H[3];
e = H[4];
f = H[5];
g = H[6];
h = H[7];
//进行64次循环:算法使用64个32位字的消息列表、8个32位工作变量以及8个32位字的散列值。
for (j = 0; j < 64; j++) {
if (j < 16) w[j] = m[j + i];
else {
var gamma0x = w[j - 15],
gamma1x = w[j - 2],
gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^
((gamma0x << 14) | (gamma0x >>> 18)) ^
(gamma0x >>> 3),
gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^
((gamma1x << 13) | (gamma1x >>> 19)) ^
(gamma1x >>> 10);
w[j] = gamma0 + (w[j - 7] >>> 0) +
gamma1 + (w[j - 16] >>> 0);
}
//执行散列计算
var ch = e & f ^ ~e & g,
maj = a & b ^ a & c ^ b & c,
sigma0 = ((a << 30) | (a >>> 2)) ^
((a << 19) | (a >>> 13)) ^
((a << 10) | (a >>> 22)),
sigma1 = ((e << 26) | (e >>> 6)) ^
((e << 21) | (e >>> 11)) ^
((e << 7) | (e >>> 25));
t1 = (h >>> 0) + sigma1 + ch + (K[j]) + (w[j] >>> 0);
t2 = sigma0 + maj;
h = g;
g = f;
f = e;
e = (d + t1) >>> 0;
d = c;
c = b;
b = a;
a = (t1 + t2) >>> 0;
}
//计算中间散列值
H[0] = (H[0] + a) | 0;
H[1] = (H[1] + b) | 0;
H[2] = (H[2] + c) | 0;
H[3] = (H[3] + d) | 0;
H[4] = (H[4] + e) | 0;
H[5] = (H[5] + f) | 0;
H[6] = (H[6] + g) | 0;
H[7] = (H[7] + h) | 0;
}
//
return H;
}
//接受前台传过来的值转化后,对每一小段继续计算来影响初始值哈希初值H 并进行最终的计算。
self.addEventListener('message', function (event) {
var uint8_array, message, block, nBitsTotal, output, nBitsLeft, nBitsTotalH, nBitsTotalL;
uint8_array = new Uint8Array(event.data.message);
message = bytesToWords(uint8_array);
block = event.data.block;
//防止短时间内内存溢出
event = null;
uint8_array = null;
output = {
'block': block
};
// 如果是文件的最后一块则最终计算结果
if (block.end === block.file_size) {
nBitsTotal = block.file_size * 8;
nBitsLeft = (block.end - block.start) * 8;
nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
nBitsTotalL = nBitsTotal & 0xFFFFFFFF;
message[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsTotal % 32);
message[((nBitsLeft + 64 >>> 9) << 4) + 14] = nBitsTotalH;
message[((nBitsLeft + 64 >>> 9) << 4) + 15] = nBitsTotalL;
self.hash = sha256(message, self.hash);
//最终结果
output.result = bytesToHex(wordsToBytes(self.hash));
} else {
//如果不是最后一块则计算的hash存入H(n)
self.hash = sha256(message, self.hash);
}
message = null;
self.postMessage(output);
}, false)
版权声明:本文为risingfine原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。