亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript使用多線程實(shí)現(xiàn)一個(gè)大文件上傳

 更新時(shí)間:2024年11月05日 11:11:56   作者:Lemonjing  
這篇文章主要為大家詳細(xì)介紹了JavaScript使用多線程實(shí)現(xiàn)一個(gè)大文件上傳的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下

開發(fā)者: JavaScript,你給我把這十個(gè)G的文件處理一下,給文件分分片,每個(gè)分片給我計(jì)算一個(gè)hash值,服務(wù)端拿到hash值就可以知道這個(gè)分片已經(jīng)上傳過了(斷點(diǎn)續(xù)傳),還有整個(gè)文件也計(jì)算一下,說不定整個(gè)文件都上傳過了(重復(fù)文件不用多次上傳)。

JavaScript: 這活你給我干是吧,我直接給你瀏覽器卡死。

const CHUNK_SIZE = 5 * 1024 * 1024; // 分片大小
async function getFile(file) {
  const result = [];
  const chunkLength = Math.ceil(file.size / CHUNK_SIZE);
  for (let i = 0; i < chunkLength; i++) {
    const chunk = await getChunk(file, CHUNK_SIZE, i);
    result.push(chunk);
  }
}

function getChunk(file, size, index) {
  return new Promise((resolve, reject) => {
    const start = index * size;
    const end = start + size;
    const chunkFile = file.slice(start, end);
    const fr = new FileReader();
    fr.onload = function(e) {
      const arrBuffer = e.target.result;
      const hash = SparkMD5.ArrayBuffer.hash(arrBuffer);
      resolve({
        start,
        end,
        chunkFile,
        index,
        hash
      })
    }
    fr.readAsArrayBuffer(chunkFile);
  })
}

JavaScript:開心不,不動(dòng)了吧,讓你不聽我的,還嘚瑟不?開發(fā)者: 不是吧,阿sir,你來真的?。?/p>

為什么JavaScript要撂挑子呢?

在瀏覽器的事件循環(huán)中,我們知道不同的線程會(huì)處理不同的任務(wù),默認(rèn)的線程比如 http 線程、io 線程等等。

如果我們想在瀏覽器中進(jìn)行復(fù)雜的計(jì)算,如果都在主線程操作,那么主線程就會(huì)阻塞,導(dǎo)致頁面的響應(yīng)不及時(shí),造成卡頓。

有沒有什么辦法可以讓主線程和計(jì)算線程分離呢?

答案當(dāng)然是webworker啦

webworker 允許我們開啟一個(gè)單獨(dú)的線程,去處理一些復(fù)雜的計(jì)算任務(wù),當(dāng)計(jì)算完成之后,通過回調(diào)的形式通知主線程,主線程只要處理拿到計(jì)算結(jié)果之后的邏輯就可以了。

那我們就來學(xué)學(xué)怎么使用

1. 創(chuàng)建一個(gè) worker 實(shí)例

const worker = new Worker("./worker.js");
// 如果需要指定worker的js可以使用ESM,可以添加type參數(shù)
const worker = new Worker("./worker.js", { type: "module" });

2. 告訴 worker 開始工作

這個(gè)worker是剛剛創(chuàng)建時(shí)候的wokerjs里面的代碼哦

worker.postMessage("開始工作");

3. 監(jiān)聽 worker 的消息

worker.onmessage = (e) => {
  // 內(nèi)部worker執(zhí)行完了,或者執(zhí)行到某個(gè)節(jié)點(diǎn)了
};

4. 關(guān)閉 worker

worker.terminate();

5. worker 內(nèi)部如何與主線程通信

self.onmessage = (e) => {
  // 收到了外部worker的消息
  // 復(fù)雜邏輯
  self.postMessage("計(jì)算完成");
};

讓worker代替主線程執(zhí)行復(fù)雜計(jì)算

const CHUNK_SIZE = 5 * 1024 * 1024; // 分片大小
const worker = new Worker('./worker.js', {
  type: 'module'
});

fileDom.onchange = function(e) {
  const file = e.target.files[0];
  worker.postMessage([file, CHUNK_SIZE]);
}
// worker.js
self.onmessage = async (e) => {
  const [file, CHUNK_SIZE] = e.data;
  const result = [];
  const chunkLength = Math.ceil(file.size / CHUNK_SIZE);
  for (let i = 0; i < chunkLength; i++) {
    const chunk = await getChunk(file, CHUNK_SIZE, i);
    result.push(chunk);
  }
  // 處理完成了
  self.postMessage(result);
}

function getChunk(file, size, index) {
  return new Promise((resolve, reject) => {
    const start = index * size;
    const end = start + size;
    const chunkFile = file.slice(start, end);
    const fr = new FileReader();
    fr.onload = function(e) {
      const arrBuffer = e.target.result;
      const hash = SparkMD5.ArrayBuffer.hash(arrBuffer);
      resolve({
        start,
        end,
        chunkFile,
        index,
        hash
      })
    }
    fr.readAsArrayBuffer(chunkFile);
  })
}

線程嘛,開了一個(gè)就有倆,仨。。。

// 直接開啟四個(gè)worker
const MAX_WORKER_NUM = 4;
const workers = new Array(MAX_WORKER_NUM).fill(0).map(() => new Worker('./worker.js', { type: 'module' }));
const wholeFileWorker = new Worker('./hashWholeFile.js', { type: 'module' });
let finishedCount = 0;
fileDom.onchange = function(e) {
  const file = e.target.files[0];
  // 計(jì)算一下一共有多少個(gè)分片
  const chunkLength = Math.ceil(file.size / CHUNK_SIZE);
  // 每一個(gè)worker要完成多少分片
  // 假如有99個(gè)分片,那第一個(gè)worker要處理1-25,第二個(gè)26-50,第三個(gè)51-75,第四個(gè)76-99
  // 我們是程序員,所以每一個(gè)index都要-1
  const workerSize = Math.ceil(chunkLength / MAX_WORKER_NUM);
  for(let i = 0; i < MAX_WORKER_NUM; i++) {
    const worker = workers[i];
    // 幫worker計(jì)算好分片任務(wù)的起始位置和結(jié)束位置
    const startIndex = i * workerSize;
    const endIndex = Math.min(start + workerSize, chunkLength);
    worker.postMessage([file, CHUNK_SIZE, startIndex, endIndex]);
    worker.onmessage = (e) => {
      finishedCount++;
      worker.terminate();
      // 計(jì)算完一部分的hash就可以開始上傳了,每一個(gè)返回結(jié)果里面有index,可以告訴后端傳遞的是哪個(gè)分片,信息已經(jīng)足夠了
      
    }
  }
  // 前面先計(jì)算分片的hash,有分片計(jì)算好的hash就可以直接開始上傳了
  wholeFileWorker.postMessage([file]);
  wholeFileWorker.onmessage = (e) => {
    // 最后處理整個(gè)文件的hash
    // 這樣整體效果就是,用戶選擇文件之后,可以快速的開始上傳進(jìn)度條,
    // 如果是之前上傳了部分,并且開始上傳的分片之前已經(jīng)上傳好了,那么可以快速跳過這些分片,直接上傳剩下的分片
    // 如果之前整個(gè)文件都上傳了,那么進(jìn)度條會(huì)從很少的地方直接跳到100%
  }

}
// worker.js
import "./md5.min.js"
self.onmessage = async (e) => {
  const [file, CHUNK_SIZE, startIndex, endIndex] = e.data;
  const result = [];
  for (let i = startIndex; i < endIndex; i++) {
    const chunk = await getChunk(file, CHUNK_SIZE, i);
    result.push(chunk);
  }
  // 處理完成了
  self.postMessage(result);
}

function getChunk(file, size, index) {
  return new Promise((resolve, reject) => {
    const start = index * size;
    const end = start + size;
    const chunkFile = file.slice(start, end);
    const fr = new FileReader();
    fr.onload = function(e) {
      const arrBuffer = e.target.result;
      const hash = SparkMD5.ArrayBuffer.hash(arrBuffer);
      resolve({
        start,
        end,
        chunkFile,
        index,
        hash
      })
    }
    fr.readAsArrayBuffer(chunkFile);
  })
}

// hashWholeFile.js
import "./md5.min.js"
self.onmessage = (e) => {
  const [file] = e.data;
  const hash = SparkMD5.ArrayBuffer.hash(file);
  self.postMessage(hash);
}

到此這篇關(guān)于JavaScript使用多線程實(shí)現(xiàn)一個(gè)大文件上傳的文章就介紹到這了,更多相關(guān)JavaScript大文件上傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解如何在Javascript和Sass之間共享變量

    詳解如何在Javascript和Sass之間共享變量

    這篇文章主要介紹了詳解如何在Javascript和Sass之間共享變量,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 微信小程序全局?jǐn)?shù)據(jù)共享和分包圖文詳解

    微信小程序全局?jǐn)?shù)據(jù)共享和分包圖文詳解

    全局?jǐn)?shù)據(jù)共享是為了解決組件之間數(shù)據(jù)共享的問題,下面這篇文章主要給大家介紹了關(guān)于微信小程序全局?jǐn)?shù)據(jù)共享和分包的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • JavaScript 大數(shù)據(jù)相加的問題

    JavaScript 大數(shù)據(jù)相加的問題

    寫一個(gè)函數(shù)處理大數(shù)據(jù)的相加問題,所謂的大數(shù)據(jù)是指超出了整型,長整型之類的常規(guī)數(shù)據(jù)類型表示范圍的數(shù)據(jù)。實(shí)現(xiàn)語言不限。
    2011-08-08
  • javaScript中with函數(shù)用法實(shí)例分析

    javaScript中with函數(shù)用法實(shí)例分析

    這篇文章主要介紹了javaScript中with函數(shù)用法,實(shí)例分析了javascript中with的功能、定義及相關(guān)使用技巧,需要的朋友可以參考下
    2015-06-06
  • 解決input輸入框僅支持輸入數(shù)字及兩位小數(shù)點(diǎn)的限制

    解決input輸入框僅支持輸入數(shù)字及兩位小數(shù)點(diǎn)的限制

    這篇文章主要為大家介紹了解決input輸入框僅支持輸入數(shù)字及兩位小數(shù)點(diǎn)的限制技巧示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Javascript新手入門之字符串拼接與變量的應(yīng)用

    Javascript新手入門之字符串拼接與變量的應(yīng)用

    這篇文章主要給大家介紹了關(guān)于Javascript新手入門之字符串拼接與變量應(yīng)用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 微信小程序文章列表功能完整實(shí)例

    微信小程序文章列表功能完整實(shí)例

    這篇文章主要介紹了微信小程序文章列表功能,結(jié)合完整實(shí)例形式詳細(xì)分析了微信小程序文章列表功能具體布局、樣式、功能相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2020-06-06
  • JavaScript中的this關(guān)鍵字用法詳解

    JavaScript中的this關(guān)鍵字用法詳解

    在編寫JavaScript應(yīng)用的時(shí)候,我們經(jīng)常會(huì)使用this關(guān)鍵字。那么this關(guān)鍵字究竟是怎樣工作的,它的設(shè)計(jì)有哪些好的地方,有哪些不好的地方,本文帶大家全面系統(tǒng)地認(rèn)識(shí)這個(gè)老朋友,感興趣的小伙伴可以借鑒閱讀
    2023-05-05
  • BootStrap數(shù)據(jù)表格實(shí)例代碼

    BootStrap數(shù)據(jù)表格實(shí)例代碼

    本文通過實(shí)例代碼給大家分享了BootStrap數(shù)據(jù)表格的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2017-09-09
  • 前端插件之Bootstrap Dual Listbox使用教程

    前端插件之Bootstrap Dual Listbox使用教程

    這篇文章主要介紹了前端插件之Bootstrap Dual Listbox使用教程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2019-07-07

最新評論