HTML5中的Web Workers

http://www.javashuo.com/article/p-mqjznazm-g.htmljavascript

http://www.javashuo.com/article/p-xvypszop-h.htmlhtml

HTML5 工做線程原理

傳統上的線程能夠解釋爲輕量級進程,它和進程同樣擁有獨立的執行控制,通常狀況下由操做系統負責調度。而在 HTML5 中的多線程是這樣一種機制,它容許在 Web 程序中併發執行多個 JavaScript 腳本,每一個腳本執行流都稱爲一個線程,彼此間互相獨立,而且由瀏覽器中的 JavaScript 引擎負責管理。下面咱們將詳細講解 HTML5 的工做線程原理。java

Web Workers 是瀏覽器內置的線程因此能夠被用來執行非阻塞事件循環的 JavaScript 代碼。node

在 HTML5 中引入的工做線程使得瀏覽器端的 JavaScript 引擎能夠併發地執行 JavaScript 代碼,從而實現了對瀏覽器端多線程編程的良好支持。將可能耗費較長時間的處理交給後臺執行,則對用戶在前臺頁面中執行的操做沒有影響。git

HTML5 中的 Web Worker 能夠分爲兩種不一樣線程類型,一個是專用線程 Dedicated Worker,一個是共享線程 Shared Worker。兩種類型的線程各有不一樣的用途。github

應用場景一:使用工做線程作後臺數值複雜(算法)計算web

應用場景二:使用共享線程處理多用戶併發鏈接算法

應用場景三:高頻的用戶交互編程

應用場景四:監聽由後臺服務器廣播的消息canvas

 

例子:

//worker.js
onmessage =function (evt){
var d = evt.data;//經過evt.data得到發送來的數據
postMessage( d );//將獲取到的數據發送會主線程
}

HTML頁面:test.html

複製代碼
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript">
//WEB頁主線程
var worker =new Worker("worker.js"); //建立一個Worker對象並向它傳遞將在新線程中執行的腳本的URL
worker.postMessage("hello world"); //向worker發送數據
worker.onmessage =function(evt){ //接收worker傳過來的數據函數
console.log(evt.data); //輸出worker發送來的數據
}
</script>
</head>
<body></body>
</html>
複製代碼

使用web worker主要分爲如下幾部分:

WEB主線程:

1.經過 worker = new Worker( url ) 加載一個JS文件來建立一個worker,同時返回一個worker實例。

2.經過worker.postMessage( data ) 方法來向worker發送數據。

3.綁定worker.onmessage方法來接收worker發送過來的數據。

4.可使用 worker.terminate() 來終止一個worker的執行。

worker新線程:

1.經過postMessage( data ) 方法來向主線程發送數據。

2.綁定onmessage方法來接收主線程發送過來的數據。

 

Web Workers可以爲用戶作些什麼?

加載一個JavaScript文件,進行大量的複雜計算,而不掛起主進程,並經過postMessage和onMessage進行通訊。

能夠在WoOer(worker)中經過importScripts(url)方法加載另外的JavaScript腳本文件。

可使用setTimeout()、clearTimeout()、setInterval()和clearInterval()。

可使用XMLHttpRequest進行異步請求。

能夠訪問navigator的部分屬性。

可使用JavaScript核心對象。

監聽由後臺服務器廣播的消息。

web Workers的侷限性:

1.不能跨域加載JS

2.worker內代碼不能訪問DOM()、window 對象、document 對象、parent 對象

3.各個瀏覽器對Worker的實現不大一致,例如FF裏容許worker中建立新的worker,而Chrome中就不行

4.不是每一個瀏覽器都支持這個新特性

 

 

 

ECMscript規定的一些基本語法以及規定的一些操做。以下操做:

•navgator :  ppVersion、userAgent、platform
•location  :   全部屬appName、a性都是隻讀的
•self  :  指向全局 worker 對象
•全部的ECMA對象,Object、Array、Date等
•XMLHttpRequest構造器
•setTimeout和setInterval方法
•close()方法,馬上中止worker運行
•importScripts方法

 

Web Workers 最佳使用場景

迄今爲止,咱們列舉了 Web Workers 的長處及其限制。讓咱們看看他們的最佳使用場景:

  • 射線追蹤:射線追蹤是一項經過追蹤光線的路徑做爲像素來生成圖片的渲染技術。Ray tracing 使用 CPU 密集型計算來模仿光線的路徑。思路即模仿一些諸如反射,折射,材料等的效果。全部的這些計算邏輯能夠放在 Web Worker 中以免阻塞 UI 線程。甚至更好的方法即-你能夠輕易地把把圖片的渲染拆分在幾個 workers 中進行(即在各自的 CPU 中進行計算,意思是說利用多個 CPU 來進行計算,能夠參考下 nodejs 的 api)。這裏有一個使用 Web Workers 來進行射線追蹤的簡單示例-https://nerget.com/rayjs-mt/r...
  • 加密:端到端的加密因爲對保護我的和敏感數據日益嚴格的法律規定而變得愈來愈流行。加密有時候會很是地耗時,特別是若是當你須要常常加密不少數據的時候(好比,發往服務器前加密數據)。這是一個使用 Web Worker 的絕佳場景,由於它並不須要訪問 DOM 或者利用其它魔法-它只是純粹使用算法進行計算而已。一旦在 worker 進行計算,它對於用戶來講是無縫地且不會影響到用戶體驗。
  • 預取數據:爲了優化網站或者網絡應用及提高數據加載時間,你可使用 Workers 來提早加載部分數據以備不時之需。不像其它技術,Web Workers 在這種狀況下是最棒噠,由於它不會影響程序的使用體驗。
  • 漸進式網絡應用:即便在網絡不穩定的狀況下,它們必須快速加載。這意味着數據必須本地存儲於瀏覽器中。這時候 IndexDB 及其它相似的 API 就派上用場了。大致上說,一個客戶端存儲是必須的。爲了避免阻塞 UI 線程的渲染,這項工做必須由 Web Workers 來執行。呃,當使用 IndexDB的時候,能夠不使用 workers 而使用其異步接口,可是以前它也含有同步接口(可能會再次引入 ),這時候就必須在 workers 中使用 IndexDB。

    這裏須要注意的是在現代瀏覽器已經不支持同步接口了,具體可查看這裏

  • 拼寫檢查:一個基本的拼寫檢測器是這樣工做的-程序會讀取一個包含拼寫正確的單詞列表的字典文件。字典會被解析成一個搜索樹以加快實際的文本搜索。當檢查器檢查一個單詞的時候,程序會在預構建搜索樹中進行檢索。若是在樹中沒有檢索到,則會經過提供替代的字符爲用戶提供替代的拼寫並檢測單詞是不是有效-是不是用戶須要的單詞。這個檢索過程當中的全部工做均可以交由 Web Worker 來完成,這樣用戶就只需輸入單詞和語句而不會阻塞 UI,與此同時 worker 會處理全部的搜索和服務建議。

 

例子:

實際工做過程會遇到用戶須要經過解析遠程圖片來得到圖片 base64 的案例,那麼這時候,若是圖片很是大,就會形成 canvas 的 toDataURL 操做至關的耗時,從而阻塞頁面的渲染。

因此解決思路即把這裏的處理圖片的操做交由 worker 來處理。如下貼出主要的代碼:

<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>Canvas to base64</title> </head> <body> <script> function loadImageAsync(url) { if (typeof url !== 'string') { return Promise.reject(new TypeError('must specify a string')); } return new Promise(function(resolve, reject) { const image = new Image(); // 容許 canvas 跨域加載圖片 image.crossOrigin="anonymous"; image.onload = function() { const $canvas = document.createElement('canvas'); const ctx = $canvas.getContext('2d'); const width = this.width; const height = this.height; let imageData; $canvas.width = width; $canvas.height = height; ctx.drawImage(image, 0, 0, width, height); imageData = ctx.getImageData(0, 0, $canvas.width, $canvas.height); resolve({image, imageData}); }; image.onerror = function() { reject(new Error('Could not load image at ' + url)); }; image.src = url; }); } function blobToDataURL(blob) { return new Promise((fulfill, reject) => { let reader = new FileReader(); reader.onerror = reject; reader.onload = (e) => fulfill(reader.result); reader.readAsDataURL(blob); }) } document.addEventListener("DOMContentLoaded", function () { loadImageAsync('https://cdn-images-1.medium.com/max/1600/1*4lHHyfEhVB0LnQ3HlhSs8g.png') .then(function (image) { // jpeg-web-worker.js https://github.com/kentmw/jpeg-web-worker const worker = new Worker('jpeg-web-worker.js'); worker.postMessage({ image: image.imageData, quality: 50 }); worker.onmessage = function(e) { // e.data is the imageData of the jpeg. {data: U8IntArray, height: int, width: int} // you can still convert the jpeg imageData into a blog like this: const blob = new Blob( [e.data.data], {type: 'image/png'} ); blobToDataURL(blob).then((imageURL) => { console.log('imageUrl:', imageURL); }) } }) .catch(function (err) { console.log('Error:', err.message); }); }); </script> </body> </html>

以上是經過 canvas 來獲取圖片數據,那麼是否有其它方法呢?確定有的啦,動下腦筋吧少年。

相關文章
相關標籤/搜索