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

瀏覽器的多線程和單線程

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

1. 單線程原因

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

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

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

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

3. web worker誕生

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

4. 適用場景

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

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

5. 函數(shù)介紹

5.1 創(chuàng)建

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

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

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

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

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

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

運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

5.3 主線程接受消息

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

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

運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

5.4 線程加載腳本

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

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

運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

5.5 關(guān)閉線程

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

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

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

6.1 什么是全排列

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

6.2 為什么使用多線程處理

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

6.3 代碼示例

實(shí)例演示
預(yù)覽 復(fù)制
復(fù)制成功!
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; 
charset=UTF-8">
<title>JavaScript實(shí)現(xiàn)全排列</title>
<script type="text/JavaScript">
function combine() {//點(diǎn)擊按鈕向webworker線程發(fā)送請(qǐng)求  
    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>
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

worker.js 代碼如下:

實(shí)例演示
預(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ù)請(qǐng)求
    var msg = message.data;
    if(msg == "") postMessage("請(qǐng)輸入正確的字符串");
    else {
        var data = msg.split("");//將字符串轉(zhuǎn)數(shù)組
        postMessage(getGroup(data));
    }
}
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

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

7. 總結(jié)

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