前端最基礎的就是 HTML+CSS+Javascript
。掌握了這三門技術就算入門,但也僅僅是入門,現在前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS
),本着提升技術水平,打牢基礎知識的中心思想,我們開課啦(每週四)。
JS 是單線程,事件循環模型。使用上來說如果有大量、高強度的計算會導致 UI渲染進程卡頓。
按照 FPS: 60 來計算 1000ms/60 = 16.666ms。我們一段程序的佔用時間需要低於16.666ms。
Web Workers 用法
new Worker(url)
,將會在 worker 線程中運行代碼,該環境與主線程不同。
因爲並不是瀏覽器環境,所以 DOM、window 是無法使用的。當然也有一些API可以使用 localstroage、websocket、indexDB、XMLHttpRequest 等是沒問題的。
同時分爲兩種環境。
- 獨享模式:DedicatedWorkerGlobalScope (一個專用線程對應一個主線程)
- 共享模式:SharedWorkerGlobalScope(一個共享線程對應多個主線程)
主線程和 worker線程 之間使用 postMessage()
方法來發送信息,通過 onmessage
這個事件監聽來接收信息。
數據的傳輸方式爲傳遞副本,而不是直接共享數據。所以也導致有時傳遞的損耗高於計算的損耗。
當然,也支持整體內存移交給 worker,不過這樣使用的話,主線程就訪問不了這塊內容了。
測試地址
worker
獨享線程(Dedicated Web Worker),只能由創建時的主線程使用。
//html
wk = new Worker('/static/workers/1190000020913212.js');
demo2.addEventListener('click', function(){
wk.postMessage(str)
})
//1190000020913212.js
onmessage = function(e) {
var str = e.data;
console.time('reportString');
console.log(str.length, str.split('').join('+').length)
console.timeEnd('reportString');
}
Shared Worker
同域被多個窗口 多個腳本運行時,可以用於通信。
比如 iframe、標籤頁。
// html
swkPIP = new SharedWorker('/static/workers/1190000020913212-SharedWorker-pip.js');
swkPIP.port.start();
swkPIP.port.postMessage(args)
// worker.js
var portArr = [];
onconnect = function(e) {
var port = e.ports[0];
portArr.push(port)
port.addEventListener('message', function(e) {
console.log(self, e, port)
if(e.data.type == 'private'){
port.postMessage(['pip', e.data]);
}else if(e.data.type == 'public'){
portArr.forEach(v=>v.postMessage(['pip', e.data]))
}else if(e.data.type == 'publicNoSelf'){
portArr.forEach(v=>v!=port&&v.postMessage(['pip', e.data]))
}
});
port.start(); // Required when using addEventListener. Otherwise called implicitly by onmessage setter.
}
從實現代碼中可以看到。
Shared Worker 需要使用 prot
通道。還需要 start()
開啓通道。
可以實現的效果
- 跨窗口通信
- 比如說有一些輪詢的接口,在多窗口的場景中會形成密集的訪問。如果我們把請求轉入Shared Worker,Shared Worker中做節流。拉回數據再通知各個窗口。
- 比如用戶在一個窗口中登錄,把登錄狀態通知給其他窗口。
Service Workers
用於瀏覽器到服務器之前的代理服務。可以實現離線訪問、攔截請求、更新緩存等。navigator.serviceWorker.register('/static/js/sw-20190621.js')
其他事項
通過URL.createObjectURL()創建URL對象,可以實現創建內嵌的worker
開啓worker需要一個同源的URL。有時我們也不需要一個這樣的文件,那麼我們就可以通過一個指向內存的URL。
// worker.js
var str = `
var i = 0;
function test(){
postMessage(++i);
setTimeout(test, 1000);
}
test();
`;
// html
var blob = new Blob([str]);
var wk = new Worker(window.URL.createObjectURL(blob));
通過轉讓對象來傳遞數據
默認情況下,主線程與 worker 之前的數據傳遞是通過拷貝,也就是JSON.stringify()之後再發送,接受使用JSON.parse()處理。
這樣使用起來在會損耗一部分在序列化與反序列化中。
所以 worker 給我們提供了一種更高效的方式,將整塊數據傳入(整塊內存移交,再源環境將不可訪問)。
myWorker.postMessage(uInt8Array, [uInt8Array]);
通過postMessage
的第二個入參,我們把uInt8Array
對象整個發送出去。
執行環境的上下文
我們都知道 瀏覽器環境的上下文和Node環境的上下文是不一樣的,其中有一些是瀏覽器環境中獨有的。worker環境也是不一樣。
其中 self 指向當前環境的 global,與 Window 不是同一個對象,而是 WorkerGlobalScope
。
微信公衆號:前端linong