<dfn id="w48us"></dfn><ul id="w48us"></ul>
  • <ul id="w48us"></ul>
  • <del id="w48us"></del>
    <ul id="w48us"></ul>
  • 深入理解JavaScript中的并行處理的介紹

    時間:2024-10-14 00:52:53 JavaScript 我要投稿
    • 相關推薦

    有關深入理解JavaScript中的并行處理的介紹

      前言

      為什么說多線程如此重要?這是個值得思考的問題。一直以來,派生線程以一種優雅的方式實現了對同一個進程中任務的劃分。操作系統負責分配每個線程的時間片,具有高優先級并且任務繁重的線程將分配到更多的時間片,而低優先級空閑的線程只能分到較少的時間片。

      雖然多線程如此重要,但JavaScript卻并沒有多線程的能力。幸運的是,隨著 Web Worker 的普及,我們終于可以在后臺線程來處理資源密集型的計算了。而不好的方面是,目前制定的標準只適用于當前的生態系統,這有時候就比較尷尬了。如果你了解其他從一開始就支持多線程的語言的話,你可能會發現很多的限制,遠非僅僅是實例化一個新線程,然后你操控這個實例就能實現多線程。

      這篇文章主要來介紹 Web Worker,包括什么時候使用,該怎么使用,它有什么奇怪的特性,會介紹在 Webpack 中如何使用它,還有可能遇到的一些坑。

      一、Web Workers

      Web Worker 可能是在 JavaScript 中唯一可以真正實現多線程的方法了。我們需要按照下面的方式創建 worker :

      const worker = newWorker("worker.js");

      上面就定義了一個 Worker 實例,然后你可以通過 postMessage 與 worker 通信,就像和 iFrame 通信一樣,只不過不存在跨域的問題,不需要驗證跨域。

      worker.postMessage(num);

      在 worker 代碼中,你需要監聽這些事件:

      onmessage = (e) => { // e.data will contain the value passed};

      這種方式是雙向的,所以你也可以從 worker 中 postMessage 給我們的主程序。

      在 worker 代碼中:

      postMessage(result);

      在主程序中:

      worker.onmessage = (e) => {}

      這就是 worker 最基本的用法。

      異常處理

      在你的 worker 代碼中,有很多種方式來處理異常,比如你可以 catch 之后通過 postMessage 傳遞,這樣可能需要多些一些代碼,但是確實最有效也最安全的。

      另一種方式是用 onerror 事件,這種方式可以捕捉所有未處理的異常,并且交給調用方來決定如何處理。調用方式很簡單:

      worker.onerror = (e) => {};

      為了調試方便,異常對象中還有一些額外的字段比如:filename,lineno,colno.

      回收

      將不需要的 worker 回收是非常重要的,worker 會生成真正的操作系統線程,如果你發現與很多 worker 線程同時運行,你可以通過很簡單的殺掉瀏覽器進程。

      你有兩種方式殺掉 worker 進程:在 worker 里和在 worker 外。我認為最好的處理 worker 生命周期的地方是在主頁面里,但這也要取決于你代碼的具體情況。

      殺掉一個 worker 實例,在外部可以直接調用 terminate()方法,這種方法可以立即殺掉它,釋放所有它正在使用的資源,如果它正在運行,也會立即終止。

      如果你想要讓 worker 自己去管理它的生命周期,可以直接在 worker 代碼中調用stop()方法。

      不管使用哪種方法,worker 都會停止,銷毀所有資源。

      如果你想使用一種“一次性”的 worker,比如需要做一些復雜運算之后就不再使用了,也要確保在 onerror 事件中去銷毀它們,這樣有利于規避一些難以發現的問題。

      worker.onerror = (e) => { worker.terminate(); reject(e);};worker.onmessage = (e) => { worker.terminate(); resolve(e.data);}

      二、行內 Workers

      有些時候將 worker 代碼寫到一個外部文件可能會使原本簡單的問題變得復雜,幸運的是,workers 也可以用一個 Blob 來初始化。

      寫一個行內 worker ,參考如下代碼段:

      // Put your worker code here

      const code = URL.createObjectURL(new Blob([ document.getElementById("worker").textContent]));const worker = new Worker(code);

      這樣你就創建了一個全局的 ObjectURL,但別忘了當不需要的時候要銷毀它:

      worker.terminate();URL.revokeObjectURL(code);

      三、Workers 嵌套

      理論上,你可以嵌套使用 worker,就像在主線程中定義一個 worker 一樣。這里有一個簡單的 例子。但是不幸的是在 Chrome 中一直存在一個 bug ,讓我們不能愉快的玩耍,或許以后這個 bug 會修復,但是目前來說還是沒有太多進展,所以你最好不要使用。

      數據傳遞

      在 worker 數據傳遞的過程中有些需要注意的邊緣情況。你可以傳遞數值,字符串,數組,也可以傳遞序列化/反序列化的對象。然而,你卻不應該依賴序列化來保持數據結構,實際上,postMessage 用到了一種 數據克隆算法,它會生成一些額外的屬性比如 RegExps 和 Blobs 以及一些循環引用。

      這就是說,你需要將你要傳遞的數據最小化。你不可以傳遞 functions ,即使是支持的類型也會有一些限制,這些也很容易產生一些難以發現的 bug。如果你將你的 API 定義為只傳遞字符串,數值,數組和對象的話,那你可能會避過這些問題。

      循環引用

      如果你有一個很復雜的對象,那么里面很可能存在循環引用,這時如果你將它序列化成 JSON,你將會得到一個 TypeError: Converting circular structure to JSON.

      let a = {};let b = {a};a.b = b;JSON.stringify({a,b}); // Error

      然而你可以在 postMessage 中放心的使用,從而你就可以在 worker 中使用。

      Transferable objects

      為了防止同時修改同一變量的場景,你傳遞給 postMessage 的所有變量都會復制一份,這樣確保了你多個線程不會修改同一個變量。但如果你想要傳一個非常大的數據的話,你就會發現復制操作是很慢的。比如,如果你在做一些圖片相關的運算,你可能會傳遞整個圖片信息,就可能會遇到復制性能的瓶頸。

      好在有 transferable object ,用 transfer 來代替 copy,比如ArrayBuffer 是transferable對象,而我們可以把任何類型的對象放在 ArrayBuffer 中。

      如果你 transfer 一個對象,之前擁有它的線程被鎖定權限,它確保了數據沒有復制之前,不會被同時修改。

      這時 postMessage 的代碼段就有點尷尬了:

      const ab = new ArrayBuffer(100);console.log(ab.byteLength); // 100worker.postMessage(ab, [ab]);console.log(ab.byteLength); // 0

      確保在 postMessage 中傳遞第二個參數,否則數據將會被復制。

      const ab = new ArrayBuffer(100);console.log(ab.byteLength); // 100worker.postMessage(ab);console.log(ab.byteLength); // 100

      四、Webpack

      在 Webpack 中使用 Web worker 時,你需要用 worker-loader。將它添加到 package.json 中的 devDependencies,然后運行 npm install,就可以了。

      用到 worker 時,只需要 require 它。

      const workerCode = require("worker!./worker.js");...const worker = new workerCode();

      這樣就初始化了 worker,然后就像上面講的一樣使用 worker。

      如果需要使用行內 worker,你需要傳遞 inline 參數給 loader。

      const workerCode = require("worker?inline!./worker.js");...const worker = new workerCode();

      在 worker 中你也可以 import 模塊。

      import fibonacci from "./fibonacci.js";...const result = fibonacci(num);

      缺點

      在 Webpack 中使用 worker 很簡單,但是在使用時也有一些坑值得你注意。

      首先,無法將代碼共用部分提取出來。如果你的 worker 中依賴一段共用代碼,你只能把代碼添加到 worker 中,不管其他地方是否也用到同樣的代碼。而且如果你多個 worker 要用同樣的庫,你也需要在每個 worker 中引入它們。

      你可能會想如果你不用 worker-loader,然后用CommonsChunkPlugin指定一個新的入口,可能會解決這個問題。但是不幸的是 worker 不像是瀏覽器 window ,一些 feature 不可用,所以一些代碼必須要引入。

      同時,用行內 worker 也不會解決問題,共用的代碼依然會出現在多個地方。

      第二點缺點是,行內 worker 可能會導致 ObjectURLs內存泄露.它們被創建出來以后就不會被釋放。這雖然不是一個大問題,但是如果你有很多“一次性” worker 的話,就會影響性能。

      綜上所述,我個人建議是使用標準的 worker,注意在 worker 中引入了什么。還要注意使用緩存。

      五、IFrames Web worker

      IFrames Web worker 和 IFrame 很像,而且印象中 IFrame 也可以實現多線程。但是 IFrame 存在一些不是線程安全 API,比如 DOM 相關,瀏覽器不能為他們生成新的線程,參考這里.

      在 IFrame 跨域中,很多 API 它都沒有權限,也只能通過 postMessage,就像 Web Worker 一樣。理論上,瀏覽器可以在不同的線程中運行 IFrame,也就可以用 IFrame 實現多線程。

      但是實際并非如此,它還是單線程的,瀏覽器不會給它們額外的線程。

      總結

      Web Worker 解決了 JavaScript 一直以來的大難題,盡管它的語法有些奇怪而且有很多限制,但是它卻可以真真正正的解決問題。從另外一方面來講,它也還是個嬰兒,某些方面還不是很成熟,不能讓我們完全依賴,所以這個技術普及還有一段距離,目前適用場景也比較局限。所以說,如果你需要做多線程,不要再等待其他的什么技術,學習 web worker 的邊緣問題,避開它的坑,你就可以很好的提高用戶體驗。以上就是這篇文章的全部內容,希望對大家能有所幫助。

    【深入理解JavaScript中的并行處理的介紹】相關文章:

    對javascript的理解03-29

    javascript面向對象中的對象怎么理解03-30

    淺談javascript中的單線程理解03-30

    淺談如何深入學習Javascript中的this關鍵字04-02

    理解JavaScript原型鏈教程03-30

    javascript編程異常處理的方法03-31

    javascript的閉包概念怎么理解03-29

    在Java中執行JavaScript代碼04-01

    Javascript中typeof 用法歸納04-01

    主站蜘蛛池模板: 亚洲午夜成人精品电影在线观看| 亚洲精品成人区在线观看| 久久夜色撩人精品国产| 500av大全导航精品| 亚洲av无码成人精品区在线播放| 夜色www国产精品资源站| 久久精品一本到99热免费| 欧美ppypp精品一区二区| 99热成人精品国产免男男| 久久精品国产亚洲AV大全| 欧美精品色精品一区二区三区| 四虎精品影院永久在线播放| 精品人妻va出轨中文字幕| 亚洲国产精品自在拍在线播放| 国产精品嫩草影院一二三区| 精品999久久久久久中文字幕| 久久亚洲国产成人精品性色| 四库影院永久四虎精品国产| 国产色婷婷精品综合在线| 亚洲精品一二区| 国产精品欧美亚洲韩国日本不卡| 久久精品国产亚洲精品2020| 中文字幕精品一区二区精品| 久久精品成人欧美大片| 国产精品天干天干在线综合| 91无码人妻精品一区二区三区L| 国产精品第13页| 国产精品亚洲A∨天堂不卡| 无码囯产精品一区二区免费| 亚洲精品tv久久久久久久久久| 久久露脸国产精品| 黑人巨大精品欧美一区二区| 国产精品内射久久久久欢欢| 国产精品亚洲精品日韩已方| www夜片内射视频日韩精品成人| 精品一区二区三区在线视频| 国产成人精品免费午夜app| 99久久99久久久精品齐齐| 国产产无码乱码精品久久鸭 | 四虎国产精品成人| 欧美精品在线视频|