第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

瀏覽器的多線程和單線程

學(xué)習(xí)過 JavaScript 的可能會了解,JavaScript 的宿主瀏覽器只有一個線程運行 JavaScript,除了 JavaScript 的線程,瀏覽器中單個頁面還有一些其他線程,例如:UI 線程負(fù)責(zé)處理渲染 DOM 元素;GUI 線程用于處理與用戶交互的邏輯;網(wǎng)絡(luò)線程用于發(fā)送接收 HTTP 請求;file 線程用于讀取文件;定時器線程處理定時任務(wù)等等。

1. 單線程原因

為什么不能像很多高級語言一樣支持多線程呢?假定 JavaScript 同時有兩個線程,一個線程在HTML中創(chuàng)建了一個標(biāo)簽元素,另一個線程刪除了這個標(biāo)簽,這時瀏覽器應(yīng)該執(zhí)行什么操作?瀏覽器中 JavaScript 的主要用途是操作 DOM 。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。為了避免復(fù)雜性,大部分主流瀏覽器的 JavaScript 運行環(huán)境只支持單線程。

2. JavaScript 的事件驅(qū)動

既然 JavaScript 只支持單線程,那么有人可能會好奇為什么瀏覽器中的 JavaScript 可以同時發(fā)送多個網(wǎng)絡(luò)請求或者執(zhí)行多個事件回調(diào)函數(shù)呢?

這是因為 JavaScript 是基于事件驅(qū)動,當(dāng)需要進(jìn)行網(wǎng)絡(luò)請求時,JavaScript 線程會把請求發(fā)送給 network 線程執(zhí)行,并等待執(zhí)行結(jié)果;當(dāng)進(jìn)行文件讀取時則調(diào)用 file 線程,然后等待結(jié)果。然后 JavaScript 會一直輪詢事件庫 event loop,直到有事件完成,這時瀏覽器會驅(qū)動 JavaScript 去執(zhí)行事件的回調(diào)函數(shù)。這就是 JavaScript 的事件驅(qū)動模型。

3. web worker誕生

單線程的最大問題是不能利用多核 CPU 的優(yōu)點,HTML5 推出的 Web Worker 標(biāo)準(zhǔn),允許 JavaScript 創(chuàng)建多線程,但是子線程受主線程約束,且不得操作 DOM 。所以,這個新標(biāo)準(zhǔn)不會產(chǎn)生多線程同步的問題。

4. 適用場景

Web Worker 能解決傳統(tǒng)的 JavaScript 單線程出現(xiàn)的執(zhí)行阻塞問題,因而適合以下幾種業(yè)務(wù)場景:

  • 并行計算;
  • ajax 輪詢;
  • 耗時的函數(shù)執(zhí)行;
  • 數(shù)據(jù)預(yù)處理/加載。

5. 函數(shù)介紹

5.1 創(chuàng)建

初始化一個 Web Worker,由于不是所有的瀏覽器都支持 Web Worker,所以需要判斷一下瀏覽器是否支持:

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!

if (window.Worker) {//判斷瀏覽器是否支持web worker
    var worker = new Worker('test.js');//創(chuàng)建一個線程,參數(shù)為需要執(zhí)行的JavaScript文件
}
運行案例 點擊 "運行案例" 可查看在線運行效果

5.2 向線程傳遞參數(shù)

新的線程的上下文環(huán)境跟原宿主環(huán)境相對獨立的,所以變量作用域不同,如果需要互相讀取變量的話需要通過消息發(fā)送的方式傳輸變量,例如:

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!
worker.postMessage('test'); //數(shù)據(jù)類型可以是字符串
worker.postMessage({method: 'echo', args: ['Work']});//數(shù)據(jù)類型可以是對象

運行案例 點擊 "運行案例" 可查看在線運行效果

5.3 主線程接受消息

跟上述場景類似,主線程也需要通過監(jiān)聽的方式獲取輔線程的消息:

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!
worker.onmessage = function (event) {
  console.log('接收到消息: ' + event.data);
}

運行案例 點擊 "運行案例" 可查看在線運行效果

5.4 線程加載腳本

子線程內(nèi)部也可以通過函數(shù)加載其他腳本:

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!
importScripts('script1.js','script2.js');

運行案例 點擊 "運行案例" 可查看在線運行效果

5.5 關(guān)閉線程

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!

// 主線程中關(guān)閉子線程
worker.terminate();
// 子線程關(guān)閉自身
self.close();
運行案例 點擊 "運行案例" 可查看在線運行效果

6. 使用 JavaScript 多線程實現(xiàn)非阻塞全排列

6.1 什么是全排列

從 n 個不同元素中任取 m(m≤n)個元素,按照一定的順序排列起來,叫做從 n 個不同元素中取出 m 個元素的一個排列。當(dāng) m=n 時所有的排列情況叫全排列。

6.2 為什么使用多線程處理

這里并非突出使用 JavaScript 實現(xiàn)全排列的優(yōu)勢,而是在實際項目中類似這種科學(xué)運算相關(guān)的算法可能會消耗一定的 CPU,由于 JavaScript 是解釋型語言,運算性能是它的弱項,而且瀏覽器中運行的 JavaScript 又是單線程的,所以一旦出現(xiàn)性能問題可能會導(dǎo)致線程阻塞,阻塞之后會導(dǎo)致頁面卡頓,非常影響用戶體驗。使用 webworker 的多線程功能將這個運算函數(shù)單獨 fork 出一個子線程去運行,運行完成之后發(fā)送結(jié)果給主線程,可以有效的避免性能問題。

6.3 代碼示例

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; 
charset=UTF-8">
<title>JavaScript實現(xiàn)全排列</title>
<script type="text/JavaScript">
function combine() {//點擊按鈕向webworker線程發(fā)送請求  
    var worker = new Worker('http://wiki-code.oss-cn-beijing.aliyuncs.com/html5/js/worker.js');
    worker.postMessage(document.getElementById("str").value);
        worker.onmessage= function (event) {                        
	        document.getElementById("result").innerHTML  =   event.data ; //監(jiān)聽JavaScript線程的結(jié)果
	    };
}
</script>
</head>
<body>
    <input type="text" id="str" />
    <button onclick="combine()">全排列</button>
    結(jié)果是:<div id="result" style="width:500px;height:500px;word-break: break-all;"></div>
</body>
</html>
運行案例 點擊 "運行案例" 可查看在線運行效果

worker.js 代碼如下:

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!

function getGroup(data, index = 0, group = []) {//生成全排列
    var need_apply = new Array();
    need_apply.push(data[index]);
    for(var i = 0; i < group.length; i++) {
        need_apply.push(group[i] + data[index]);
    }
    group.push.apply(group, need_apply);
    if(index + 1 >= data.length) return group;
    else return getGroup(data, index + 1, group);
}
onmessage = function(message){//監(jiān)聽主線程的數(shù)據(jù)請求
    var msg = message.data;
    if(msg == "") postMessage("請輸入正確的字符串");
    else {
        var data = msg.split("");//將字符串轉(zhuǎn)數(shù)組
        postMessage(getGroup(data));
    }
}
運行案例 點擊 "運行案例" 可查看在線運行效果

上述代碼實現(xiàn)了一個使用 JavaScript 的 Web Worker 實現(xiàn)的全排列的功能。上半部分是主線程的代碼,主要實現(xiàn)了創(chuàng)建子線程、發(fā)送數(shù)據(jù)給子線程、接收子線程的消息這幾個功能;下半部分是子線程,子線程主要負(fù)責(zé)運算,并將運算結(jié)果發(fā)送給主線程。

7. 總結(jié)

早期的 JavaScript 由于考慮操作 DOM 的一致性問題,以及當(dāng)時的網(wǎng)頁沒有過多的交互所以不需要大量的計算,所以只支持單線程。這在多核 CPU 時代的劣勢愈發(fā)明顯,所以 HTML5 中推出多線程解決這個問題?;仡櫛菊轮饕榻B了 Web Worker 的使用方式以及其適用場景。