Web Worker 詳細介紹 - 原文連接javascript
[TOC]html
咱們都知道JavaScript
這個語言在執行的時候是採用單線程進行執行的,也就是說在同一時間只能作一件事,這也和這門語言有很大的關係,採用同步執行的方式進行運行,若是出現阻塞,那麼後面的代碼將不會執行,HTML5則提出了web Worker標準,表示JavaScript
容許有多個線程,可是子線程徹底受主線程的控制,切子線程不能操做DOM,只有主線程能夠操做DOM,因此以主線程爲主的單線程執行原理成了JavaScript
這門語言的核心。關於JavaScript
的運行機制能夠參考阮一峯的文章JavaScript 運行機制詳解:再談Event Loopjava
下面咱們來講說web worker
究竟是什麼,簡單明瞭的一句話其實就是在Javascript
單線程執行的基礎上,開啓一個子線程,進行程序處理,而不影響主線程的執行,當子線程執行完畢以後再回到主線程上,在這個過程當中並不影響主線程的執行過程。
舉個例子:
傳統狀況下,執行下面的代碼後,整個頁面都會被凍結,因爲javascript
是單線程處理,以下代碼已經徹底組塞了後續的執行web
while(true){}
若是換一種方式,咱們經過開啓一個新的線程來執行這段代碼,將他放在一個單獨的worker.js
文件中,在主線程執行如下代碼。chrome
var worker = new Worker("worker.js")
在建立線程的時候須要給實例化的Worker
傳入惟一一個參數,指向一個javascript
文件資源的url或者Blob對象(Blob對象就是一個包含有隻讀原始數據類文件對象),調用這個構造函數以後,一個線程就被建立了,以下:編程
var worker = new Worker("worker.js"); var worker = new Worker(blob);
Web Worker
的基本原理就是在當前的主線程中加載一個只讀文件來建立一個新的線程,兩個線程同時存在,且互不阻塞,而且在子線程與主線程之間提供了數據交換的接口postMessage
和onmessage
。來進行發送數據和接收數據。其數據格式能夠爲結構化數據(JSON
等);
當咱們建立了一個worker實例以後,咱們能夠經過以下兩種方式來發送數據:瀏覽器
var worker = new Worker("worker.js"); //實例化對象 //第一種傳遞方式 worker.postMessage(message,taransferList); //第二種傳遞方式 worker.postMessage({ operation: "list_all_users", //ArrayBuffer object input: buffer, threshold: 0.8, }, [buffer]);
若是要想一個專用線程發送數據,那麼咱們須要使用線程中的 postMessage 方法。專用線程不只僅支持傳輸二進制數據,也支持結構化的 JavaScript 數據格式。在這裏有一點須要注意,爲了高效地傳輸 ArrayBuffer 對象數據,須要在 postMessage 方法中的第二個參數中指定它。
同時咱們若是須要接收某個線程傳來的數據可使用onmessage
來進行接收,方法以下:多線程
//方法一 worker.onmessage = function(event){ var data = event.data; //經過event.data來獲取傳入的參數 } //方法二 worker.addEventListener("message",target);
下面是一段運行在chrome中的參數傳遞方式:函數
index.html 工具
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>webWorker</title> </head> <body> <script> var worker = new Worker("worker.js"); worker.postMessage("123456"); worker.onmessage = function (e) { console.log(e.data) }; </script> </body> </html>
worker.js
onmessage = function (e) { console.log(e.data); postMessage("2222") };
此時咱們的瀏覽器打印出的log是以下:
上面咱們已經說了建立一個新的線程、傳遞數據、接收數據的方法,下面再次作一個精簡的回顧。
var worker = new Worker("worker.js")
worker.postMessage("text");
worker.onmessage = function (e) { var message = e.data; };
worker.onerror = function(e){ console.log("error at "+e.filename ":" + e.lineno + e.message) }
worker.terminate();
importScripts("./utils/base64.js","./utils/map.js"...)
須要注意的是importScripts
是同步方法,一旦importScripts
方法返回就能夠開始使用載入的腳本,而不須要回調函數。
當咱們建立一個新的worker時,改代碼會運行在一個全新的javascript的環境中(WorkerGlobalScope)運行,是徹底和建立worker的腳本隔離,這時咱們能夠吧建立新worker的腳本叫作主線程,而被建立的新的worker叫作子線程。
WorkerGlobalScope是worker的全局對象,因此它包含全部核心javascript全局對象擁有的屬性如JSON等,window的一些屬性,也擁有相似於XMLHttpRequest()等。
可是咱們所開啓的新的worker也就是子線程,並不支持操做頁面的DOM。
共享線程是爲了不線程的重複建立和銷燬過程,下降了系統性能的消耗,共享線程SharedWorker
能夠同時有多個頁面的線程連接。
使用SharedWorker
建立共享線程,也須要提供一個javascript腳本文件的URL地址或Blob,該腳本文件中包含了咱們在線程中須要執行的代碼,以下:
var worker = new SharedWorker("sharedworker.js");
共享線程也使用了message
事件監聽線程消息,但使用SharedWorker對象的port屬性與線程通訊以下。
worker.port.onmessage = function(e){ ... }
同時咱們也可使用SharedWorker對象的port屬性向共享線程發送消息以下。
worker.port.postMessage("message");
文章大部分類容摘自《指尖上行》一書
參考文獻
一、JavaScript 運行機制詳解:再談Event Loop —— 阮一峯
二、深刻 HTML5 Web Worker 應用實踐:多線程編程