HTML5中我以爲最有用和激動人心的功能就是引入了線程的概念,從而咱們能夠用多線程的思想來處理比較複雜的應用。咱們可讓前臺線程去完成和用戶交互的工做,而把比較複雜的,耗時較長的運算放在後臺線程中完成,而讓前臺線程與後臺線程經過消息交互.(注意:後臺線程是不能夠直接操做window對象和dom樹的)javascript
建立後臺線程的核心就是HTML5 提供的 Workers API ,下面是我用這個API開發一個相對比較複雜的應用。html
假設咱們有一個需求,頁面上有一個輸入框,讓用戶輸入一個整數,而後計算出全部小於這個整數的素數,而後把全部的素數分別計算平方,最後吧結果顯示在主頁面上。java
若是不用HTML5,那麼將會是很是長的一段JS代碼,並且若是輸入的值比較大時,它會吧整個頁面所有「凍結」,有了HTML5就輕鬆許多了,咱們分工以下:json
主線程:把主頁面上的輸入框的中的數發送給後臺線程1數組
後臺線程1:根據這個數來找到全部比它小的素數,而後把這些素數封裝在一個JSON數組中發送給主線程,同時把這一步驟的處理時間發送給主線程多線程
主線程:收到後臺線程發過來的信息,而後把素數列表發給後臺線程2dom
後臺線程2:對於素數列表中的每個素數,計算求出其平方,而後把全部的結果以JSON數組形式發送給主線程,同時把這一步驟的處理時間發送給主線程ide
主線程:把後臺線程1,後臺線程2所獲得的結果以及每一個線程執行各自所用的時間顯示在主頁面上指定id的區域內函數
因此,咱們首先要有個主頁面,用來接受用戶輸入和最終顯示結果,這個頁面代碼以下:post
- <!DOCTYPE HTML>
- <html>
- <head>
- <meta
- charset="utf-8"
- />
- <title>HTML5 線程交互例子</title>
- <script
- type="text/javascript"
- src="js/mainthread.js"
- >
- </script>
- </head>
- <body>
- <p>這個例子演示HTML5中的Worker的用法,它可讓主線程和多個後臺線程合做來完成一項任務</p>
- <p>步驟概述:
- <p>主線程:把主頁面上的輸入框的中的數發送給後臺線程1</p>
- <p>後臺線程1:根據這個數來找到全部比它小的素數,而後把這些素數封裝在一個字符串對象中發送給主線程,同時把這一步驟的處理時間發送給主線程</p>
- <p>主線程收到後臺線程發過來的信息,而後把素數列表發給後臺線程2</p>
- <p>後臺線程2:對於素數列表中的每個素數,計算求出其平方,而後把全部的結果發送給主線程,同時把這一步的處理時間發送給主線程</p>
- <p>主線程:構造html頁面,顯示出每一個步驟的處理時間,以及最終顯示結果</p>
- <br>
- 輸入一個正整數:
- <input type="text" id="inputedInteger"/>
- <input type="button" value="點擊讓主線程把這個數值發送給後臺線程1" onclick="handleInputInteger()"/>
- <p id="result"></p>
- </body>
- </html>
其次,咱們來構建主線程,它主要任務就是進行協調和調度,它先取得用戶輸入,而後發送消息給後臺工做線程1,以後接收從後臺工做線程1返回的內含素數數組的消息,並把這個數組發給後臺工做線程2,再接收從後臺工做線程2中返回的內含素數平方數組的消息,最終把全部消息彙總而後打印在主頁面上,細節請看個人代碼註釋:
mainthread.js
- //這個函數是頁面上點擊button的事件處理函數
- function handleInputInteger(){
- //讓window對象建立第一個後臺線程(worker1),這個後臺線程專門負責獲得小於等於某個整數的全部素數
- var worker1= new Worker("js/worker1-getPrimeList.js");
- //獲取用戶輸入的整數並轉爲10進制
- var integerInput=document.getElementById("inputedInteger").value;
- var num=parseInt(integerInput,10);
- //把從用戶輸入的整數傳給後臺線程1
- worker1.postMessage(num);
- //當獲取從後臺線程1(worker1)傳遞過來的結果時,咱們處理這個結果,咱們這個結果是個json對象
- worker1.onmessage=function(event){
- //取得從後臺線程1(worker1)返回的JSON對象,而且分離出信息
- //其中primeArray是由後臺線程1(worker1)完成的取得全部<=指定整數的素數構成的素數數組(仍是未解析的JSON數組)
- //而worker1ElapsedTime則是後臺線程1(worker1)完成它的工做的用時,單位毫秒
- var data = event.data;
- var dataInfo=JSON.parse(data);
- var primeArray=dataInfo.primeArray;
- var worker1ElapsedTime=dataInfo.worker1ElapsedTime;
- //咱們讓主線程建立第二個後臺線程(worker2),這個後臺線程能夠把全部的素數計算平方
- var worker2 = new Worker("js/worker2-getSquaredPrimeList.js");
- //把primeArray的信息發送給第二個後臺線程(worker2)
- worker2.postMessage(primeArray);
- //當得到從後臺線程2(worker2)傳來的結果時,咱們在主頁面上構造信息塊,反映出整個過程
- worker2.onmessage=function(event){
- //取得從後臺線程2(worker2)返回的JSON對象,而且分離出信息
- //primeArray是從主線程傳遞給後臺線程2(worker2)的素數數組
- //squaredPrimeArray是由後臺線程2(worker2)完成的全部的素數的平方構成的數組
- //而worker2ElapsedTime則是後臺線程2(worker2)完成它的工做的用時,單位毫秒
- var data = event.data;
- var dataInfo=JSON.parse(data);
- var primeArray=dataInfo.primeArray;
- var squaredPrimeArray=dataInfo.squaredPrimeArray;
- var worker2ElapsedTime=dataInfo.worker2ElapsedTime;
- //取得素數的個數
- var numOfPrimes=JSON.parse(primeArray).length;
- //構造信息文本,而且顯示在頁面上id爲"result"的區域
- var result=document.getElementById("result");
- var resultStr="用戶輸入的整數爲: "+num+"<br>";
- resultStr+="<br>";
- resultStr+="後臺線程1(worker1)通過分析可知,小於該整數的素數一共有"+numOfPrimes+"個。"+"<br>";
- resultStr+="後臺線程1(worker1)獲得了素數數組爲:"+primeArray+"<br>";
- resultStr+="後臺線程1(worker1)的操做用時爲: "+worker1ElapsedTime+"毫秒!"+"<br>";
- resultStr+="<br>";
- resultStr+="後臺線程2(worker2)獲得的素數的平方數組爲:"+squaredPrimeArray+"<br>";
- resultStr+="後臺線程2(worker2)的操做用時爲: "+worker2ElapsedTime+"毫秒!"+"<br>";
- result.innerHTML=resultStr;
- }
- };
- }
再次,咱們來定義後臺工做線程1(worker1),這個線程必須被包含在一個js文件中,它必須定義當接收從主線程傳來的消息(一個整數)時的處理函數,它會構造一個小於這個整數的全部素數組成的素數數組,並把這個素數數組返回給調用者線程(主線程)、固然了,咱們還須要一個輔助方法來判斷某個整數是否爲素數,因此worker1-getPrimeList.js的代碼以下:
- //這個函數用於判斷某個數是否爲素數
- function isPrime(number) {
- if (number < 2) {
- return false;
- } else {
- for (var j = 2; j <= Math.sqrt(number); j++) {
- if (number % j == 0) {
- return false;
- }
- }
- }
- return true;
- }
- // 這個js代碼能夠接收傳入的整數而且返回全部小於等於這個整數的素數列表
- onmessage = function(event) {
- //計算開始時間
- var beginTime = new Date().getTime();
- // 獲取用戶輸入的整數
- var num = event.data;
- // 構造一個buffer素數數組
- var bufferedPrimeArray = new Array(num);
- var primeArrayMaxIndex=0;
- for (var i = 0; i < num; i++) {
- if (isPrime(i)){
- bufferedPrimeArray[primeArrayMaxIndex]=i;
- primeArrayMaxIndex++;
- }
- }
- //構造真正的素數數組
- var primeArray = new Array(primeArrayMaxIndex);
- //將buffer素數數組中的全部的素數移動到這個數組中
- for(var j=0;j<primeArrayMaxIndex;j++){
- primeArray[j]=bufferedPrimeArray[j];
- }
- //計算結束時間
- var endTime= new Date().getTime();
- var elapsedTime=endTime-beginTime;
- //構造json對象來存儲信息:
- var data = new Object;
- data.primeArray = JSON.stringify(primeArray);
- data.worker1ElapsedTime= elapsedTime;
- var str=JSON.stringify(data);
- //把這個json對象發送回主線程 (也就是建立這個worker1的線程)
- postMessage(str);
- }
最後,咱們來定義後臺工做線程2(worker2),這個線程也必須被包含在一個js文件中,它必須定義當接收從主線程傳來的消息(一個素數數組)時的處理函數,它會構造一個對應的素數平方數組,並把這個素數數組,以及素數平方數組返回給調用者線程(主線程),因此worker2-getSquaredPrimeList.js的代碼以下:
- // 這個 js代碼能夠把傳入的素數數組中每一個素數依次求平方,而後構造一個素數平方數組
- onmessage = function(event) {
- //計算開始時間
- var beginTime = new Date().getTime();
- // 獲取從主線程傳來的素數數組,而且還原成真正的素數數組
- var primeArrayFromMainThread= event.data;
- var primeArray = JSON.parse(primeArrayFromMainThread);
- var length=primeArray.length;
- //構造一個素數平方數組
- var squaredPrimeArray=new Array(length);
- //將原來數組中的全部素數依次求平方,而後填充到這個新的平方數組中
- for (var i=0;i<length;i++){
- squaredPrimeArray[i]=primeArray[i]* primeArray[i];
- }
- //計算結束時間
- var endTime= new Date().getTime();
- var elapsedTime=endTime-beginTime;
- //構造json對象來存儲信息:
- var data = new Object;
- data.primeArray = JSON.stringify(primeArray);
- data.squaredPrimeArray=JSON.stringify(squaredPrimeArray);
- data.worker2ElapsedTime= elapsedTime;
- var str=JSON.stringify(data);
- //把這個json對象發送回主線程 (也就是建立這個worker1的線程)
- postMessage(str);
- }
最後國際慣例,咱們演示下例子:
首先,用戶輸入前:
用戶輸入某個整數,好比98,則顯示以下: