js快速计算文件hash值
1. 通過 requestIdleCallback or spark-md5利用瀏覽器空閑時(shí)間切片計(jì)算文件hash值:
requestIdleCallback簡介:
window.requestIdleCallback(): 方法將 在瀏覽器的空閑時(shí)段內(nèi)調(diào)用的函數(shù)排隊(duì)。這使開發(fā)者能夠在主事件循環(huán)上執(zhí)行后臺和低優(yōu)先級工作,而不會影響延遲關(guān)鍵事件,如動畫和輸入響應(yīng)。函數(shù)一般會按先進(jìn)先調(diào)用的順序執(zhí)行,然而,如果回調(diào)函數(shù)指定了執(zhí)行超時(shí)時(shí)間timeout,則有可能為了在超時(shí)前執(zhí)行函數(shù)而打亂執(zhí)行順序。
file_hash.vue
<script> import sparkMD5 from 'spark-md5'export default { methods: {async uploadFile() {const hash = await fileHash()console.log("文件哈希是:", hash)...},async fileHash() {const chunks = []let cur = 0while (cur < this.file.size) { // this.file 為 e.target.files[0]chunks.push({ index: cur, file: this.file.slice(cur, cur + 1 * 1024 * 1024)}) // 1MB/片cur += size}return new Promise( resolve => {const spark = new sparkMD5.ArrayBuffer()let count = 0const appendToSpark = async file => {return new Promise( resolve => {const reader = new FileReader()reader.readAsArrayBuffer(file)reader.onload = e => {spark.append(e.target.result)resolve()}})}const workLoop = async deadline => {while (count < chunks.length && deadline.timeRemaining() > 1) {//瀏覽器存在空閑時(shí)間await appendToSpark(chunks[count].file)count++if (count < chunks.length) {this.hashProgress = Number( ((100 * count) / chunks.length).toFixed(2) )} else {this.hashProgress = 100resolve(spark.end())}}window.requestIdleCallback(workLoop) // 給 workLoop 函數(shù)一個(gè)瀏覽器狀態(tài)參數(shù) deadline}window.requestIdleCallback(workLoop) // 給 workLoop 函數(shù)一個(gè)瀏覽器狀態(tài)參數(shù) deadline})} } </script>2. 通過 Worker spark-md5 快速切片計(jì)算文件hash值:
Worker介紹:
Web Worker 的作用,就是為 JavaScript 創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker線程,將一些任務(wù)分配給后者運(yùn)行。在主線程運(yùn)行的同時(shí),Worker線程在后臺運(yùn)行,兩者互不干擾。等到 Worker 線程完成計(jì)算任務(wù),再把結(jié)果返回給主線程。這樣的好處是,一些計(jì)算密集型或高延遲的任務(wù),被 Worker 線程負(fù)擔(dān)了,主線程(通常負(fù)責(zé) UI 交互)就會很流暢,不會被阻塞或拖慢。
Worker 線程一旦新建成功,就會始終運(yùn)行,不會被主線程上的活動(比如用戶點(diǎn)擊按鈕、提交表單)打斷。這樣有利于隨時(shí)響應(yīng)主線程的通信。但是,這也造成了 Worker 比較耗費(fèi)資源,不應(yīng)該過度使用,而且一旦使用完畢,就應(yīng)該關(guān)閉。
目錄介紹:
├── static │ ├── hash.js //快速計(jì)算文件hash入口文件 (放在 static 文件夾是為了方便 Worker 訪問) │ └── spark-md5.min.js //需要用到 spark-md5 庫 ├── pages │ └── file_hash.vue //快速計(jì)算文件hash │ ... yarn add spark-md5 // 安裝該庫, 將其內(nèi)部的 spark-md5.min.js 文件和 hash.js放在一起共 importScripts 訪問file_hash.vue
<script> export default { methods: {async uploadFile() {const hash = await fileHash()console.log("文件哈希是:", hash)...},async fileHash() {const chunks = []let cur = 0while (cur < this.file.size) { // this.file 為 e.target.files[0]chunks.push({ index: cur, file: this.file.slice(cur, cur + 1 * 1024 * 1024)}) // 1MB切片cur += size}return new Promise( resolve => {this.worker = new Worker('/hash.js')// 開啟一個(gè)外部進(jìn)程this.worker.postMessage({ chunks }) // 給外部進(jìn)程傳遞信息 this.worker.onmessage = e => { // 接收外部Worker回傳的信息const { progress, hash } = e.datathis.hashProgress = Number(progress.toFixed(2)) //計(jì)算hash值的進(jìn)度條if (hash) {resolve(hash) // 得到計(jì)算出來的hash}}})} } </script>hash.js:
self.importScripts('spark-md5.min.js') // 引入 spark-md5self.onmessage = e => { // 接收主線程傳遞的參數(shù)const { chunks } = e.dataconst spark = new self.SparkMD5.ArrayBuffer()let progress = 0, count = 0const loadNext = index => {if (index == 0) {progress = 0count = 0}const reader = new FileReader()reader.readAsArrayBuffer(chunks[index].file)reader.onload = e => {count++spark.append(e.target.result) // 將讀取的內(nèi)容添加入spark生成hashif (count == chunks.length) {self.postMessage({progress: 100,hash: spark.end()})} else {progress += 100 / chunks.lengthself.postMessage({ progress })loadNext(count)}}}loadNext(0) }拓展:通過抽樣加快hash的計(jì)算速度
方法:抽取文件內(nèi)一部分字段放入 chunks 數(shù)組內(nèi),通過減小計(jì)算 hash 的文件大小, 來增加hash的計(jì)算速度。
缺點(diǎn):有少許可能照成誤差,對于需精確計(jì)算hash則不適用,取舍有寸即可!
例如:
<script> import sparkMD5 from 'spark-md5'export default { methods: {async calculateHashSample() {// this.file 為 e.target.files[0]const spark = new sparkMD5.ArrayBuffer(), reader = new FileReader(),file = this.file, size = file.size, offset = 2 * 1024 * 1024 // hash抽樣: 第一個(gè)區(qū)塊2M,中間區(qū)塊取前中后各2個(gè)字節(jié),最后區(qū)塊數(shù)據(jù)全要let chunks = [file.slice(0, offset)]let cur = offsetwhile (cur < size) {if (cur + offset >= size) {chunks.push(file.slice(cur, cur + offset))} else {const mid = cur + offset / 2, end = cur + offsetchunks.push(file.slice(cur, cur + 2))chunks.push(file.slice(mid, mid + 2))chunks.push(file.slice(end - 2, end))}cur += offset}this.chunks = chunks //抽樣后的區(qū)塊//下面拿去計(jì)算hash就會很快} } </script>總結(jié)
以上是生活随笔為你收集整理的js快速计算文件hash值的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信自动挑选黑名单
- 下一篇: 计算机桌面图片唐诗,古诗词高清电脑壁纸