麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > HTML > 正文

HTML5之web workers_動力節點Java學院整理

2024-08-26 00:19:47
字體:
來源:轉載
供稿:網友

專用 Web Worker (Dedicated Web Worker) 提供了一個簡單的方法使得 web 內容能夠在后臺運行腳本。一旦 worker 創建后,它可以向由它的創建者指定的事件監聽函數傳遞消息,這樣該 worker 生成的所有任務就都會接收到這些消息。worker 線程能夠在不干擾 UI 的情況下執行任務。另外,它還能夠使用XMLHttpRequest(雖然responseXML與channel 兩個屬性值始終是null)來執行I/O 操作。本文通過提供例子和細節補全了前面的文檔。提供給 worker 的函數列出了 worker 所支持的函數。

Worker接口會生成真正的操作系統級別的線程,如果你不太小心,那么并發(concurrency)會對你的代碼產生有趣的影響。然而,對于 web worker 來說,與其他線程的通信點會被很小心的控制,這意味著你很難引起并發問題。你沒有辦法去訪問非線程安全的組件或者是 DOM,此外你還需要通過序列化對象來與線程交互特定的數據。所以你要是不費點勁兒,還真搞不出錯誤來。生成 worker

創建一個新的 worker 十分簡單。你所要做的就是調用Worker()構造函數,指定一個要在 worker 線程內運行的腳本的 URI,如果你希望能夠收到 worker 的通知,可以將 worker 的onmessage屬性設置成一個特定的事件處理函數。

var myWorker = new Worker("my_task.js");myWorker.onmessage = function (oEvent) {  console.log("Called back by the worker!/n");};

或者,你也可以使用addEventListener():

var myWorker = new Worker("my_task.js");myWorker.addEventListener("message", function (oEvent) {  console.log("Called back by the worker!/n");}, false);myWorker.postMessage(""); // start the worker.

例子中的第一行創建了一個新的 worker 線程。第三行為 worker 設置了message事件的監聽函數。當 worker 調用自己的postMessage() 函數時就會調用這個事件處理函數。最后,第七行啟動了 worker 線程。注意: 傳入Worker構造函數的參數 URI 必須遵循同源策略。目前,不同的瀏覽器制造商對于哪些 URI 應該遵循同源策略尚有分歧;Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0 / SeaMonkey 2.7) 及后續版本允許傳入 data URI,而 Internet Explorer 10 則不認為 Blob URI 對于 worker 來說是一個有效的腳本。

傳遞數據

在主頁面與 worker 之間傳遞的數據是通過拷貝,而不是共享來完成的。傳遞給worker 的對象需要經過序列化,接下來在另一端還需要反序列化。頁面與 worker不會共享同一個實例,最終的結果就是在每次通信結束時生成了數據的一個副本。大部分瀏覽器使用結構化拷貝來實現該特性。

在往下進行之前,出于教學的目的,讓我們創建一個名為emulateMessage()的函數,它將模擬在從worker到主頁面(反之亦然)的通信過程中,變量的「拷貝而非共享」行為:

function emulateMessage (vVal) {    return eval("(" + JSON.stringify(vVal) + ")");}// Tests// test #1var example1 = new Number(3);alert(typeof example1); // objectalert(typeof emulateMessage(example1)); // number// test #2var example2 = true;alert(typeof example2); // booleanalert(typeof emulateMessage(example2)); // boolean// test #3var example3 = new String("Hello World");alert(typeof example3); // objectalert(typeof emulateMessage(example3)); // string// test #4var example4 = {    "name": "John Smith",    "age": 43};alert(typeof example4); // objectalert(typeof emulateMessage(example4)); // object// test #5function Animal (sType, nAge) {    this.type = sType;    this.age = nAge;}var example5 = new Animal("Cat", 3);alert(example5.constructor); // Animalalert(emulateMessage(example5).constructor); // Object

拷貝而并非共享的那個值稱為消息。再來談談worker,你可以使用postMessage() 將消息傳遞給主線程或從主線程傳送回來。message事件的data屬性就包含了從 worker 傳回來的數據。

example.html: (主頁面):

var myWorker = new Worker("my_task.js");myWorker.onmessage = function (oEvent) {  console.log("Worker said : " + oEvent.data);};myWorker.postMessage("ali");my_task.js (worker):postMessage("I/'m working before postMessage(/'ali/').");onmessage = function (oEvent) {  postMessage("Hi " + oEvent.data);};

注意:通常來說,后臺線程 – 包括 worker –無法操作 DOM。如果后臺線程需要修改 DOM,那么它應該將消息發送給它的創建者,讓創建者來完成這些操作。

如你所見,worker與主頁面之間傳輸的消息始終是「JSON 消息」,即使它是一個原始類型的值。所以,你完全可以傳輸JSON數據 和/或 任何能夠序列化的數據類型:

postMessage({"cmd": "init", "timestamp": Date.now()});

傳遞數據的例子

例子 #1: 創建一個通用的 「異步eval()」

下面這個例子介紹了,如何在 worker 內使用eval()來按順序執行異步的任何種類的 JavaScript 代碼:

// Syntax: asyncEval(code[, listener])var asyncEval = (function () {  var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D");  oParser.onmessage = function (oEvent) {    if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); }    delete aListeners[oEvent.data.id];  };  return function (sCode, fListener) {    aListeners.push(fListener || null);    oParser.postMessage({      "id": aListeners.length - 1,      "code": sCode    });  };})();

示例使用:

// asynchronous alert message...asyncEval("3 + 2", function (sMessage) {    alert("3 + 2 = " + sMessage);});// asynchronous print message...asyncEval("/"Hello World!!!/"", function (sHTML) {    document.body.appendChild(document.createTextNode(sHTML));});// asynchronous void...asyncEval("(function () {/n/tvar oReq = new XMLHttpRequest();/n/toReq.open(/"get/", /"http://www.mozilla.org//", false);/n/toReq.send(null);/n/treturn oReq.responseText;/n})()");

例子 #2:傳輸 JSON 的高級方式和創建一個交換系統

如果你需要傳輸非常復雜的數據,還要同時在主頁與 Worker 內調用多個方法,那么可以考慮創建一個類似下面的系統。

example.html(the main page):

<!doctype html><html><head><meta charset="UTF-8"  /><title>MDN Example - Queryable worker</title><script type="text/javascript">  /*    QueryableWorker instances methods:     * sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc): calls a Worker's queryable function     * postMessage(string or JSON Data): see Worker.prototype.postMessage()     * terminate(): terminates the Worker     * addListener(name, function): adds a listener     * removeListener(name): removes a listener    QueryableWorker instances properties:     * defaultListener: the default listener executed only when the Worker calls the postMessage() function directly  */  function QueryableWorker (sURL, fDefListener, fOnError) {    var oInstance = this, oWorker = new Worker(sURL), oListeners = {};    this.defaultListener = fDefListener || function () {};    oWorker.onmessage = function (oEvent) {      if (oEvent.data instanceof Object && oEvent.data.hasOwnProperty("vo42t30") && oEvent.data.hasOwnProperty("rnb93qh")) {        oListeners[oEvent.data.vo42t30].apply(oInstance, oEvent.data.rnb93qh);      } else {        this.defaultListener.call(oInstance, oEvent.data);      }    };    if (fOnError) { oWorker.onerror = fOnError; }    this.sendQuery = function (/* queryable function name, argument to pass 1, argument to pass 2, etc. etc */) {      if (arguments.length < 1) { throw new TypeError("QueryableWorker.sendQuery - not enough arguments"); return; }      oWorker.postMessage({ "bk4e1h0": arguments[0], "ktp3fm1": Array.prototype.slice.call(arguments, 1) });    };    this.postMessage = function (vMsg) {      //I just think there is no need to use call() method      //how about just oWorker.postMessage(vMsg);      //the same situation with terminate      //well,just a little faster,no search up the prototye chain      Worker.prototype.postMessage.call(oWorker, vMsg);    };    this.terminate = function () {      Worker.prototype.terminate.call(oWorker);    };    this.addListener = function (sName, fListener) {      oListeners[sName] = fListener;    };    this.removeListener = function (sName) {      delete oListeners[sName];    };  };  // your custom "queryable" worker  var oMyTask = new QueryableWorker("my_task.js" /* , yourDefaultMessageListenerHere [optional], yourErrorListenerHere [optional] */);  // your custom "listeners"  oMyTask.addListener("printSomething", function (nResult) {    document.getElementById("firstLink").parentNode.appendChild(document.createTextNode(" The difference is " + nResult + "!"));  });  oMyTask.addListener("alertSomething", function (nDeltaT, sUnit) {    alert("Worker waited for " + nDeltaT + " " + sUnit + " :-)");  });</script></head><body>  <ul>    <li><a id="firstLink" href="javascript:oMyTask.sendQuery('getDifference', 5, 3);">What is the difference between 5 and 3?</a></li>    <li><a href="javascript:oMyTask.sendQuery('waitSomething');">Wait 3 seconds</a></li>    <li><a href="javascript:oMyTask.terminate();">terminate() the Worker</a></li>  </ul></body></html>my_task.js (the worker):// your custom PRIVATE functionsfunction myPrivateFunc1 () {  // do something}function myPrivateFunc2 () {  // do something}// etc. etc.// your custom PUBLIC functions (i.e. queryable from the main page)var queryableFunctions = {  // example #1: get the difference between two numbers:  getDifference: function (nMinuend, nSubtrahend) {      reply("printSomething", nMinuend - nSubtrahend);  },  // example #2: wait three seconds  waitSomething: function () {      setTimeout(function() { reply("alertSomething", 3, "seconds"); }, 3000);  }};// system functionsfunction defaultQuery (vMsg) {  // your default PUBLIC function executed only when main page calls the queryableWorker.postMessage() method directly  // do something}function reply (/* listener name, argument to pass 1, argument to pass 2, etc. etc */) {  if (arguments.length < 1) { throw new TypeError("reply - not enough arguments"); return; }  postMessage({ "vo42t30": arguments[0], "rnb93qh": Array.prototype.slice.call(arguments, 1) });}onmessage = function (oEvent) {  if (oEvent.data instanceof Object && oEvent.data.hasOwnProperty("bk4e1h0") && oEvent.data.hasOwnProperty("ktp3fm1")) {    queryableFunctions[oEvent.data.bk4e1h0].apply(self, oEvent.data.ktp3fm1);  } else {    defaultQuery(oEvent.data);  }};

這是一個非常合適的方法,用于切換 主頁-worker - 或是相反的 - 之間的消息。

通過轉讓所有權(可轉讓對象)來傳遞數據

Google Chrome 17 與 Firefox 18 包含另一種性能更高的方法來將特定類型的對象(可轉讓對象) 傳遞給一個 worker/從 worker 傳回 。可轉讓對象從一個上下文轉移到另一個上下文而不會經過任何拷貝操作。這意味著當傳遞大數據時會獲得極大的性能提升。如果你從 C/C++ 世界來,那么把它想象成按照引用傳遞。然而與按照引用傳遞不同的是,一旦對象轉讓,那么它在原來上下文的那個版本將不復存在。該對象的所有權被轉讓到新的上下文內。例如,當你將一個ArrayBuffer對象從主應用轉讓到Worker 中,原始的ArrayBuffer被清除并且無法使用。它包含的內容會(完整無差的)傳遞給 Worker 上下文。

// Create a 32MB "file" and fill it.var uInt8Array = new Uint8Array(1024*1024*32); // 32MBfor (var i = 0; i < uInt8Array .length; ++i) {  uInt8Array[i] = i;}worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);

生成subworker

如果需要的話 Worker 能夠生成更多的 Worker。這樣的被稱為 subworker,它們必須托管在與父頁面相同的源內。同理,subworker 解析 URI 時會相對于父 worker 的地址而不是自身的頁面。這使得 worker 容易監控它們的依賴關系。 Chrome 目前并不支持subworker。

嵌入式 worker

目前沒有一種「官方」的方法能夠像<script>元素一樣將 worker 的代碼嵌入的網頁中。但是如果一個<script>元素沒有src 特性,并且它的type特性沒有指定成一個可運行的 mime-type,那么它就會被認為是一個數據塊元素,并且能夠被 JavaScript 使用。「數據塊」是 HTML5 中一個十分常見的特性,它可以攜帶幾乎任何文本類型的數據。所以,你能夠以如下方式嵌入一個 worker:

<!DOCTYPE html><html><head><meta charset="UTF-8" /><title>MDN Example - Embedded worker</title><script type="text/js-worker">  // 該腳本不會被 JS 引擎解析,因為它的 mime-type 是 text/js-worker。  var myVar = "Hello World!";  // 剩下的 worker 代碼寫到這里。</script><script type="text/javascript">  // 該腳本會被 JS 引擎解析,因為它的 mime-type 是 text/javascript。  function pageLog (sMsg) {    // 使用 fragment:這樣瀏覽器只會進行一次渲染/重排。    var oFragm = document.createDocumentFragment();    oFragm.appendChild(document.createTextNode(sMsg));    oFragm.appendChild(document.createElement("br"));    document.querySelector("#logDisplay").appendChild(oFragm);  }</script><script type="text/js-worker">  // 該腳本不會被 JS 引擎解析,因為它的 mime-type 是 text/js-worker。  onmessage = function (oEvent) {    postMessage(myVar);  };  // 剩下的 worker 代碼寫到這里。</script><script type="text/javascript">  // 該腳本會被 JS 引擎解析,因為它的 mime-type 是 text/javascript。  // 在過去...:  // 我們使用 blob builder  // ...但是現在我們使用 Blob...:  var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=/"text//js-worker/"]"), function (oScript) { return oScript.textContent; }),{type: "text/javascript"});  // 創建一個新的 document.worker 屬性,包含所有 "text/js-worker" 腳本。  document.worker = new Worker(window.URL.createObjectURL(blob));  document.worker.onmessage = function (oEvent) {    pageLog("Received: " + oEvent.data);  };  // 啟動 worker.  window.onload = function() { document.worker.postMessage(""); };</script></head><body><div id="logDisplay"></div></body></html>

現在,嵌入式 worker 已經嵌套進了一個自定義的document.worker屬性中。

超時與間隔

Worker 能夠像主線程一樣使用超時與間隔。這會十分有用,比如說,如果你想讓 worker 線程周期性而并非不間斷的運行代碼。

終止 worker

如果你想立即終止一個運行中的 worker,可以調用 worker 的terminate()方法:

myWorker.terminate();

worker 線程會被立即殺死,不會留下任何機會讓它完成自己的操作或清理工作。

Workers 也可以調用自己的nsIWorkerScope.close()方法來關閉自己:

self.close();

處理錯誤

當 worker 出現運行時錯誤時,它的onerror事件處理函數會被調用。它會收到一個實現了ErrorEvent接口名為error的事件。該事件不會冒泡,并且可以被取消;為了防止觸發默認動作,worker 可以調用錯誤事件的preventDefault()方法。錯誤事件擁有下列三個它感興趣的字段:

message

可讀性良好的錯誤消息。

filename

發生錯誤的腳本文件名。

lineno

發生錯誤時所在腳本文件的行號。

訪問 navigator 對象

Workers 可以在它的作用域內訪問navigator對象。它含有如下能夠識別瀏覽器的字符串,就像在普通腳本中做的那樣:

  • ?appName
  • ?appVersion
  • ?platform
  • ?userAgent

引入腳本與庫

Worker 線程能夠訪問一個全局函數,importScripts(),該函數允許 worker 將腳本或庫引入自己的作用域內。你可以不傳入參數,或傳入多個腳本的 URI 來引入;以下的例子都是合法的:

importScripts();                        /* 什么都不引入 */importScripts('foo.js');                /* 只引入 "foo.js" */importScripts('foo.js', 'bar.js');      /* 引入兩個腳本 */

瀏覽器將列出的腳本加載并運行。每個腳本中的全局對象都能夠被 worker 使用。如果腳本無法加載,將拋出NETWORK_ERROR異常,接下來的代碼也無法執行。而之前執行的代碼(包括使用window.setTimeout()延遲執行的代碼)卻依然能夠使用。importScripts()之后的函數聲明依然能夠使用,因為它們始終會在其他代碼之前運行。注意:腳本的下載順序不固定,但執行時會按照你將文件名傳入到importScripts()中的順序。這是同步完成的;直到所有腳本都下載并運行完畢,importScripts()才會返回。

例子

本節提供了幾個如何使用 DOM worker 的例子。

在后臺執行運算

worker 的一個優勢在于能夠執行處理器密集型的運算而不會阻塞 UI 線程。在下面的例子中,worker 用于計算斐波那契數。

JavaScript 代碼

下面的 JavaScript 代碼保存在「fibonacci.js」文件中,與下一節的 HTML 文件關聯。

var results = [];function resultReceiver(event) {  results.push(parseInt(event.data));  if (results.length == 2) {    postMessage(results[0] + results[1]);  }}function errorReceiver(event) {  throw event.data;}onmessage = function(event) {  var n = parseInt(event.data);  if (n == 0 || n == 1) {    postMessage(n);    return;  }  for (var i = 1; i <= 2; i++) {    var worker = new Worker("fibonacci.js");    worker.onmessage = resultReceiver;    worker.onerror = errorReceiver;    worker.postMessage(n - i);  } };

worker 將屬性onmessage設置為一個函數,當 worker 對象調用postMessage() 時該函數會接收到發送過來的信息。(注意,這么使用并不等同于定義一個同名的全局變量,或是定義一個同名的函數。var onmessage與function onmessage將會定義與該名字相同的全局屬性,但是它們不會注冊能夠接收從創建 worker 的網頁發送過來的消息的函數。) 這會啟用遞歸,生成自己的新拷貝來處理計算的每一個循環。

HTML 代碼

<!DOCTYPE html><html>  <head>    <meta charset="UTF-8"  />    <title>Test threads fibonacci</title>  </head>  <body>  <div id="result"></div>  <script language="javascript">    var worker = new Worker("fibonacci.js");    worker.onmessage = function(event) {      document.getElementById("result").textContent = event.data;      dump("Got: " + event.data + "/n");    };    worker.onerror = function(error) {      dump("Worker error: " + error.message + "/n");      throw error;    };    worker.postMessage("5");  </script>  </body></html>

網頁創建了一個div元素,ID 為result, 用它來顯示運算結果,然后生成 worker。在生成 worker 后,onmessage處理函數配置為通過設置div元素的內容來顯示運算結果,然后onerror處理函數被設置為轉儲錯誤信息。最后,向 worker 發送一條信息來啟動它。


注:相關教程知識閱讀請移步到HTML教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 中文字幕在线成人 | 久久久久久久91 | av在线播放观看 | 久久逼网 | 久久精品99北条麻妃 | 国产免费久久久久 | 一级免费黄色免费片 | 一级毛片播放 | www.com香蕉| 亚洲aⅴ免费在线观看 | 国产精品色在线网站 | 精品国产一区二区三区在线 | 国产精品成人av片免费看最爱 | 亚洲成人精品在线 | 久久久精品视 | 精品国产亚洲人成在线 | 欧美亚洲一级 | 在线观看免费污视频 | 成人短视频在线播放 | 久久精品视频首页 | 国产精品一区网站 | 国产午夜精品一区二区三区嫩草 | 国产 一区 | 日韩美香港a一级毛片免费 欧美一级淫片007 | 久久久精品视频免费看 | 在线看一区二区三区 | 久草热久草视频 | 免费一级毛片在线播放不收费 | 国产手机国产手机在线 | 片在线观看 | 国产中出视频 | 国内精品久久久久久2021浪潮 | 日韩精品羞羞答答 | 久久亚洲精品国产一区 | 国产一级二级在线播放 | 男女牲高爱潮免费视频男女 | 国产一级一片免费播放 | 日韩在线播放第一页 | 毛片免费视频在线观看 | 视频一区 中文字幕 | 黄色免费小网站 |