html5支持多线程,html5 多线程
html5 多線程
版本:HTML5
運行者 Worker 接口是Web Workers API 的一部分,代表一個后臺任務,它容易被創建并向創建者發回消息。創建一個運行者只要簡單的調用Worker()構造函數,指定一個腳本,在工作線程中執行。
運行者能夠依序產生新(嵌套)的運行者,只要這些運行者有同源(origin)的父頁面(注意:Blink暫時不支持嵌套 Worker)。 此外,運行者還能夠使用 XMLHttpRequest 實現網絡 I/O 操作, 只不過 XMLHttpRequest上的 responseXML 與 channel 兩個屬性值始終返回 null。
運行者 Workder 支持的函數 頁面提供了一個 worker 支持的全局函數列表。
火狐瀏覽器中, 如果在擴展使用運行者,不應使用(js-ctypes),應該使用 ChromeWorker 對象。
瀏覽器支持
Internet Explorer 10 以上版本支持
構造函數
Worker():創建一個專用Web worker,它只執行URL指定的腳本。Worker不指定URL時,而由使用Blob創建。
屬性
繼承父對象EventTarget 的屬性,以及實現對象 AbstractWorker的屬性。
事件句柄AbstractWorker.onerror:當ErrorEvent 類型的事件冒泡到 worker 時,事件監聽函數 EventListener 被調用. 它繼承于 AbstractWorker。
Worker.onmessage:當MessageEvent類型的事件冒泡到 worker 時,事件監聽函數 EventListener 被調用. 例如,一個消息通過 DedicatedWorkerGlobalScope.postMessage,從執行者發送到父頁面對象,消息保存在事件對象的 data 屬性中。
Worker.onmessageerror:當messageerror 類型的事件發生時,對應的EventHandler 代碼被調用。
方法
繼承父對象EventTarget 的方法,以及實現對象 AbstractWorker的方法。Worker.postMessage():發送一條消息到最近的外層對象,消息可由任何 JavaScript 對象組成。
Worker.terminate():立即終止 worker。該方法不會給 worker 留下任何完成操作的機會;就是簡單的立即停止。Service Woker 不支持這個方法。
示例
下面的代碼通過構造函數Worker()創建了一個 Worker 對象。
var myWorker = new Worker('worker.js');
var first = document.querySelector('#number1');
var second = document.querySelector('#number2');
first.onchange = function()
{
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
以前我們總說,JS是單線程沒有多線程,當JS在頁面中運行長耗時同步任務的時候就會導致頁面假死影響用戶體驗,從而需要設置把任務放在任務隊列中;執行任務隊列中的任務也并非多線程進行的,然而現在HTML5提供了我們前端開發這樣的能力 - Web Workers API,我們一起來看一看 Web Worker 是什么,怎么去使用它,在實際生產中如何去用它來進行產出。
1. 概述
Web Workers 使得一個Web應用程序可以在與主執行線程分離的后臺線程中運行一個腳本操作。這樣做的好處是可以在一個單獨的線程中執行費時的處理任務,從而允許主(通常是UI)線程運行而不被阻塞。
它的作用就是給JS創造多線程運行環境,允許主線程創建worker線程,分配任務給后者,主線程運行的同時worker線程也在運行,相互不干擾,在worker線程運行結束后把結果返回給主線程。這樣做的好處是主線程可以把計算密集型或高延遲的任務交給worker線程執行,這樣主線程就會變得輕松,不會被阻塞或拖慢。這并不意味著JS語言本身支持了多線程能力,而是瀏覽器作為宿主環境提供了JS一個多線程運行的環境。
不過因為worker一旦新建,就會一直運行,不會被主線程的活動打斷,這樣有利于隨時響應主線程的通性,但是也會造成資源的浪費,所以不應過度使用,用完注意關閉。或者說:如果worker無實例引用,該worker空閑后立即會被關閉;如果worker實列引用不為0,該worker空閑也不會被關閉。
看一看它的兼容性
2. 使用
2.1 限制
worker線程的使用有一些注意點同源限制:worker線程執行的腳本文件必須和主線程的腳本文件同源,這是當然的了,總不能允許worker線程到別人電腦上到處讀文件吧
文件限制:為了安全,worker線程無法讀取本地文件,它所加載的腳本必須來自網絡,且需要與主線程的腳本同源
DOM操作限制:worker線程在與主線程的window不同的另一個全局上下文中運行,其中無法讀取主線程所在網頁的DOM對象,也不能獲取document、window等對象,但是可以獲取navigator、location(只讀)、XMLHttpRequest、setTimeout族等瀏覽器API。
通信限制:worker線程與主線程不在同一個上下文,不能直接通信,需要通過postMessage方法來通信。
腳本限制:worker線程不能執行alert、confirm,但可以使用XMLHttpRequest對象發出ajax請求。
2.2 例子
在主線程中生成 Worker 線程很容易:
var myWorker = new Worker(jsUrl, options);
Worker()構造函數,第一個參數是腳本的網址(必須遵守同源政策),該參數是必需的,且只能加載 JS 腳本,否則報錯。第二個參數是配置對象,該對象可選。它的一個作用就是指定 Worker 的名稱,用來區分多個 Worker 線程。
// 主線程
var myWorker = new Worker('worker.js', { name : 'myWorker' });
// Worker 線程
self.name
關于api什么的,直接上例子大概就能明白了,首先是worker線程的js文件:
// workerThread1.js
let i = 1
function simpleCount()
{
i++
self.postMessage(i)
setTimeout(simpleCount, 1000)
}
simpleCount()
self.onmessage = ev =>
{
postMessage(ev.data + ' 呵呵~')
}
在HTML文件中的body中:
Worker 輸出內容:
發送
stop!
if (typeof(Worker) === 'undefined') // 使用Worker前檢查一下瀏覽器是否支持
document.writeln(' Sorry! No Web Worker support.. ')
else {
window.w = new Worker('workerThread1.js')
window.w.onmessage = ev => {
document.getElementById('app').innerHTML = ev.data
}
window.w.onerror = err => {
w.terminate()
console.log(error.filename, error.lineno, error.message) // 發生錯誤的文件名、行號、錯誤內容
}
function sendMessage() {
const msg = document.getElementById('msg')
window.w.postMessage(msg.value)
}
function stopWorker() {
window.w.terminate()
}
}
可以自己運行一下看看效果,上面用到了一些常用的api
主線程中的api,worker表示是 Worker 的實例:worker.postMessage: 主線程往worker線程發消息,消息可以是任意類型數據,包括二進制數據
worker.terminate: 主線程關閉worker線程
worker.onmessage: 指定worker線程發消息時的回調,也可以通過worker.addEventListener('message',cb)的方式
worker.onerror: 指定worker線程發生錯誤時的回調,也可以worker.addEventListener('error',cb)
Worker線程中全局對象為self,代表子線程自身,這時this指向self,其上有一些api:self.postMessage: worker線程往主線程發消息,消息可以是任意類型數據,包括二進制數據
self.close: worker線程關閉自己
self.onmessage: 指定主線程發worker線程消息時的回調,也可以self.addEventListener('message',cb)
self.onerror: 指定worker線程發生錯誤時的回調,也可以self.addEventListener('error',cb)
注意,w.postMessage(aMessage, transferList)方法接受兩個參數,aMessage是可以傳遞任何類型數據的,包括對象,這種通信是拷貝關系,即是傳值而不是傳址,Worker 對通信內容的修改,不會影響到主線程。事實上,瀏覽器內部的運行機制是,先將通信內容串行化,然后把串行化后的字符串發給 Worker,后者再將它還原。一個可選的 Transferable對象的數組,用于傳遞所有權。如果一個對象的所有權被轉移,在發送它的上下文中將變為不可用(中止),并且只有在它被發送到的worker中可用。可轉移對象是如ArrayBuffer,MessagePort或ImageBitmap的實例對象,transferList數組中不可傳入null。
更詳細的API參見 MDN - WorkerGlobalScope。
worker線程中加載腳本的api:
importScripts('script1.js') // 加載單個腳本
importScripts('script1.js', 'script2.js') // 加載多個腳本
3. 實戰場景
個人覺得,Web Worker我們可以當做計算器來用,需要用的時候掏出來摁一摁,不用的時候一定要收起來~加密數據:有些加解密的算法比較復雜,或者在加解密很多數據的時候,這會非常耗費計算資源,導致UI線程無響應,因此這是使用Web Worker的好時機,使用Worker線程可以讓用戶更加無縫的操作UI。
預取數據:有時候為了提升數據加載速度,可以提前使用Worker線程獲取數據,因為Worker線程是可以是用XMLHttpRequest的。
預渲染:在某些渲染場景下,比如渲染復雜的canvas的時候需要計算的效果比如反射、折射、光影、材料等,這些計算的邏輯可以使用Worker線程來執行,也可以使用多個Worker線程,這里有個射線追蹤的示例。
復雜數據處理場景:某些檢索、排序、過濾、分析會非常耗費時間,這時可以使用Web Worker來進行,不占用主線程。
預加載圖片:有時候一個頁面有很多圖片,或者有幾個很大的圖片的時候,如果業務限制不考慮懶加載,也可以使用Web Worker來加載圖片,可以參考一下這篇文章的探索,這里簡單提要一下。
// 主線程
let w = new Worker("js/workers.js");
w.onmessage = function (event) {
var img = document.createElement("img");
img.src = window.URL.createObjectURL(event.data);
document.querySelector('#result').appendChild(img)
}
// worker線程
let arr = [...好多圖片路徑];
for (let i = 0, len = arr.length; i < len; i++) {
let req = new XMLHttpRequest();
req.open('GET', arr[i], true);
req.responseType = "blob";
req.setRequestHeader("client_type", "DESKTOP_WEB");
req.onreadystatechange = () => {
if (req.readyState == 4) {
postMessage(req.response);
}
}
req.send(null);
}
在實戰的時候注意雖然使用worker線程不會占用主線程,但是啟動worker會比較耗費資源
主線程中使用XMLHttpRequest在請求過程中瀏覽器另開了一個異步http請求線程,但是交互過程中還是要消耗主線程資源
在 Webpack 項目里面使用 Web Worker 請參照:怎么在 ES6+Webpack 下使用 Web Worker
總結
以上是生活随笔為你收集整理的html5支持多线程,html5 多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 汇总上面所有,Oracle
- 下一篇: DolphinScheduler对比Ai