JS基礎(chǔ)知識(shí)儲(chǔ)備(Web Woker)

一磅叛、概述

1秽荤、介紹

“JavaScript是單線程的”這一說法它事實(shí)上描述了JavaScript環(huán)境在瀏覽器內(nèi)的一般行為纷责。

這樣的單線程范例本身是有局限的哼丈,因?yàn)樗恋K了在語言中其他可行的編程模式边器,否則可將工作委托給獨(dú)立的線程或進(jìn)程训枢。JavaScript被限定到這一單線程范例上,是為了讓它和各種瀏覽器API交互時(shí)保持兼容性忘巧。例如DOM如果被多個(gè)JavaScript線程同時(shí)修改會(huì)出現(xiàn)問題恒界。因此,不能使用傳統(tǒng)的并發(fā)結(jié)構(gòu)增強(qiáng)JavaScript砚嘴。

Web Worker 的作用十酣,就是為 JavaScript 創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker 線程际长,將一些任務(wù)分配給后者運(yùn)行耸采。在主線程運(yùn)行的同時(shí),Worker 線程在后臺(tái)運(yùn)行工育,兩者互不干擾虾宇。等到 Worker 線程完成計(jì)算任務(wù),再把結(jié)果返回給主線程如绸。這樣的好處是嘱朽,一些計(jì)算密集型或高延遲的任務(wù)旭贬,被 Worker 線程負(fù)擔(dān)了,主線程(通常負(fù)責(zé) UI 交互)就會(huì)很流暢搪泳,不會(huì)被阻塞或拖慢稀轨。
workers的核心觀點(diǎn)是:允許主執(zhí)行線程委托工作給獨(dú)立的實(shí)體,而不用改變現(xiàn)存的單線程模型岸军。

2奋刽、Web Worker與線程的比較

相同特性:

  • workers是用實(shí)際的線程實(shí)現(xiàn)的。例如Blink瀏覽器引擎使用WorkerTread實(shí)現(xiàn)workers凛膏,它對(duì)應(yīng)一個(gè)底層的平臺(tái)線程杨名。
  • workers并行執(zhí)行。盡管頁面和worker的實(shí)現(xiàn)都是單線程JavaScript環(huán)境猖毫,各個(gè)環(huán)境的指令都是并行執(zhí)行的。
  • workers可以共享一些內(nèi)存须喂。workers可以使用SharedArrayBuffer 在多環(huán)境中共享內(nèi)存吁断。線程使用鎖來實(shí)現(xiàn)并行控制,而JavaScript使用Atomics接口實(shí)現(xiàn)并行控制坞生。

不同點(diǎn):

  • workers不會(huì)共享所有內(nèi)存仔役。在傳統(tǒng)的線程模型中,多線程有能力讀寫共享內(nèi)存空間是己。除了sharedArrayBuffer之外又兵,在workers移動(dòng)數(shù)據(jù)的進(jìn)出需要對(duì)數(shù)據(jù)復(fù)制或者轉(zhuǎn)存。
  • worker線程不必是同一進(jìn)程的一部分卒废。通常沛厨,單個(gè)進(jìn)程可以在它內(nèi)部生成多個(gè)線程。取決于瀏覽器引擎的實(shí)現(xiàn)方法摔认,worker線程可以是逆皮,也可以不是頁面進(jìn)程的一部分。例如Chrome的Blink引擎使用獨(dú)立進(jìn)程實(shí)現(xiàn)共享worker和服務(wù)worker線程参袱。
  • worker線程的創(chuàng)建成本更昂貴电谣。worker線程包括自己的獨(dú)立事件循環(huán),全局對(duì)象抹蚀,事件處理程序剿牺,和其他JavaScript環(huán)境中的部分特性。創(chuàng)建這些線程的計(jì)算開銷不可忽視环壤。

注意:在形式和功能上晒来,workers都不是線程的簡(jiǎn)單替代。

workers相對(duì)更重镐捧,不建議大量使用潜索。例如臭增,對(duì)四百萬像素的圖片的每個(gè)像素都啟動(dòng)一個(gè)worker是不合適的。一般來說竹习,我們預(yù)期workers是持久性的誊抛,有較高的啟動(dòng)性能花銷,和較高的每實(shí)例內(nèi)存開銷整陌。所以拗窃,web worker有利于隨時(shí)響應(yīng)主線程的通信。但是泌辫,這也造成了 Worker 比較耗費(fèi)資源随夸,不應(yīng)該過度使用,而且一旦使用完畢震放,就應(yīng)該關(guān)閉宾毒。

二、Web Worker

1殿遂、Workers類型

(1)專用Worker

專用web worker诈铛,一般也稱為專用worker,web worker墨礁,或就叫worker幢竹,是允許腳本生成獨(dú)立JavaScript線程并委托任務(wù)的基本應(yīng)用。專用worker正如它的名字所表明的恩静,只能由創(chuàng)建它的頁面訪問焕毫。

(2)共享Worker

共享web worker的行為很像專用worker。主要的區(qū)別是共享worker可以讓多個(gè)環(huán)境訪問驶乾,包括不同的頁面邑飒。任意腳本執(zhí)行所在的源如果與最初生成共享worker的腳本所在的源相同,就可以發(fā)送和接受共享worker的消息轻掩。

(3)其他

  • ServiceWorkers (服務(wù)worker)一般作為web應(yīng)用程序幸乒、瀏覽器和網(wǎng)絡(luò)(如果可用)之前的代理服務(wù)器。它們旨在(除開其他方面)創(chuàng)建有效的離線體驗(yàn)唇牧,攔截網(wǎng)絡(luò)請(qǐng)求罕扎,以及根據(jù)網(wǎng)絡(luò)是否可用采取合適的行動(dòng)并更新駐留在服務(wù)器上的資源。他們還將允許訪問推送通知和后臺(tái)同步API丐重。
  • Chrome Workers 是一種僅適用于firefox的worker腔召。如果您正在開發(fā)附加組件,希望在擴(kuò)展程序中使用worker且有在你的worker中訪問 js-ctypes 的權(quán)限扮惦,你可以使用Chrome Workers臀蛛。詳情請(qǐng)參閱ChromeWorker
  • Audio Workers (音頻worker)使得在web worker上下文中直接完成腳本化音頻處理成為可能。

2浊仆、使用web worker的注意事項(xiàng)

(1)同源限制

分配給 Worker 線程運(yùn)行的腳本文件客峭,必須與主線程的腳本文件同源。

(2)DOM 限制

Worker 線程所在的全局對(duì)象抡柿,與主線程不一樣舔琅,無法讀取主線程所在網(wǎng)頁的 DOM 對(duì)象,也無法使用document洲劣、window备蚓、parent這些對(duì)象。但是囱稽,Worker 線程可以navigator對(duì)象和location對(duì)象郊尝。

(3)通信聯(lián)系

Worker 線程和主線程不在同一個(gè)上下文環(huán)境,它們不能直接通信战惊,必須通過消息完成流昏。

(4)腳本限制

Worker 線程不能執(zhí)行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 對(duì)象發(fā)出 AJAX 請(qǐng)求吞获。

(5)文件限制

Worker 線程無法讀取本地文件横缔,即不能打開本機(jī)的文件系統(tǒng)(file://),它所加載的腳本衫哥,必須來自網(wǎng)絡(luò)。

3襟锐、基本用法

(1)專用Worker

代碼示例:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width">

    <title>Web Workers basic example</title>

    <link rel="stylesheet" href="style.css">
    <!--[if lt IE 9]>
      <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>

  <body>
    <h1>Web<br>Workers<br>basic<br>example</h1>

    <div class="controls" tabindex="0">

      <form>
        <div>
          <label for="number1">Multiply number 1: </label>    
          <input type="text" id="number1" value="0">
        </div>
        <div>
          <label for="number2">Multiply number 2: </label>   
          <input type="text" id="number2" value="0">
        </div>
      </form>

      <p class="result">Result: 0</p>

    </div>
    <script src="main.js"></script>
  </body>
</html>
const first = document.querySelector('#number1');
const second = document.querySelector('#number2');

const result = document.querySelector('.result');

if (window.Worker) {
    const myWorker = new Worker("worker.js");

    first.onchange = function() {
      myWorker.postMessage([first.value, second.value]);
      console.log('Message posted to worker');
    }

    second.onchange = function() {
      myWorker.postMessage([first.value, second.value]);
      console.log('Message posted to worker');
    }

    myWorker.onmessage = function(e) {
        result.textContent = e.data;
        console.log('Message received from worker');
    }
} else {
    console.log('Your browser doesn\'t support web workers.')
}

onmessage = function(e) {
  console.log('Worker: Message received from main script');
  const result = e.data[0] * e.data[1];
  if (isNaN(result)) {
    postMessage('Please write two numbers');
  } else {
    const workerResult = 'Result: ' + result;
    console.log('Worker: Posting message back to main script');
    postMessage(workerResult);
  }
}

(2)共享Worker

代碼示例:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width">

    <title>Shared Workers basic example</title>

    <link rel="stylesheet" href="style.css">
    <!--[if lt IE 9]>
      <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>

  <body>
    <h1>Shared<br>Workers<br>basic<br>example</h1>

    <div class="controls" tabindex="0">

    <form>
      <div>
        <label for="number1">Multiply number 1: </label>
        <input type="text" id="number1" value="0">
      </div>
      <div>
        <label for="number2">Multiply number 2: </label>
        <input type="text" id="number2" value="0">
      </div>
    </form>

    <p class="result1">Result: 0</p>

    <p><a href="index2.html" target="_blank">Go to second worker page</a></p>

    </div>

    <script src="multiply.js"></script>
    <script src="nosubmit.js"></script>
  </body>
</html>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width">

    <title>Shared Workers basic example</title>

    <link rel="stylesheet" href="style.css">
    <!--[if lt IE 9]>
      <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>

  <body>
    <h1>Shared<br>Workers<br>basic<br>example</h1>

    <div class="controls" tabindex="0">

    <form>
      <div>
        <label for="number3">Square number: </label>
        <input type="text" id="number3" value="0">
      </div>
    </form>

    <p class="result2">Result: 0</p>

    </div>
    <script src="square.js"></script>
    <script src="nosubmit.js"></script>
  </body>
</html>
var first = document.querySelector('#number1');
var second = document.querySelector('#number2');

var result1 = document.querySelector('.result1');

if (!!window.SharedWorker) {
  var myWorker = new SharedWorker("worker.js");

  first.onchange = function() {
    myWorker.port.postMessage([first.value, second.value]);
    console.log('Message posted to worker');
  }

  second.onchange = function() {
    myWorker.port.postMessage([first.value, second.value]);
    console.log('Message posted to worker');
  }

  myWorker.port.onmessage = function(e) {
    result1.textContent = e.data;
    console.log('Message received from worker');
    console.log(e.lastEventId);
  }
}
var form = document.querySelector('form');

form.onsubmit = function(e) {
  e.preventDefault();
};
onconnect = function(e) {
  var port = e.ports[0];

  port.onmessage = function(e) {
    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
    port.postMessage(workerResult);
  }

}
onconnect = function(e) {
  var port = e.ports[0];

  port.onmessage = function(e) {
    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
    port.postMessage(workerResult);
  }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末撤逢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子粮坞,更是在濱河造成了極大的恐慌蚊荣,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莫杈,死亡現(xiàn)場(chǎng)離奇詭異互例,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)筝闹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門媳叨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人关顷,你說我怎么就攤上這事糊秆。” “怎么了议双?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵痘番,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)汞舱,這世上最難降的妖魔是什么伍纫? 我笑而不...
    開封第一講書人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮昂芜,結(jié)果婚禮上莹规,老公的妹妹穿的比我還像新娘。我一直安慰自己说铃,他們只是感情好访惜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腻扇,像睡著了一般债热。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幼苛,一...
    開封第一講書人閱讀 49,729評(píng)論 1 289
  • 那天窒篱,我揣著相機(jī)與錄音,去河邊找鬼舶沿。 笑死墙杯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的括荡。 我是一名探鬼主播高镐,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼畸冲!你這毒婦竟也來了嫉髓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤邑闲,失蹤者是張志新(化名)和其女友劉穎算行,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苫耸,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡州邢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了褪子。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片量淌。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖褐筛,靈堂內(nèi)的尸體忽然破棺而出类少,到底是詐尸還是另有隱情,我是刑警寧澤渔扎,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布硫狞,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏残吩。R本人自食惡果不足惜财忽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泣侮。 院中可真熱鬧即彪,春花似錦、人聲如沸活尊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛹锰。三九已至深胳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铜犬,已是汗流浹背舞终。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留癣猾,地道東北人敛劝。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像纷宇,于是被迫代替她去往敵國和親夸盟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348