javascript
主进程中发生了一个javascript错误_知道html5 Web Worker标准吗?能实现JavaScript的多线程?
js為什么是單線程?
主要是因?yàn)樽铋_始javascript是單純的服務(wù)于瀏覽器的一種腳步語(yǔ)言(那時(shí)候沒有nodejs)。瀏覽器是為了渲染網(wǎng)頁(yè),通過(guò)dom與用戶交互,如果一個(gè)線程需要給dom執(zhí)行click事件,而另一個(gè)進(jìn)程要?jiǎng)h除這個(gè)dom,這2個(gè)動(dòng)作可能同時(shí)進(jìn)行,也可能先后進(jìn)行(像java,c#等語(yǔ)言中會(huì)引入鎖的概念,這樣會(huì)變得異常復(fù)雜),那么就會(huì)造成很多不可預(yù)料的錯(cuò)誤。
所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成了這門語(yǔ)言的核心特征。為了利用多核CPU的計(jì)算能力,HTML5提出Web Worker標(biāo)準(zhǔn),允許JavaScript腳本創(chuàng)建多個(gè)線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個(gè)新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)。
瀏覽器是多線程的
瀏覽器打開一個(gè)tab,就會(huì)單獨(dú)開一個(gè)進(jìn)程,這個(gè)進(jìn)程包含多個(gè)線程
主要包含的線程有:
GUI渲染線程
負(fù)責(zé)渲染瀏覽器界面,解析HTML,CSS,構(gòu)建DOM樹和RenderObject樹,布局和繪制等。
當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時(shí),該線程就會(huì)執(zhí)行
注意,GUI渲染線程與JS引擎線程是互斥的,當(dāng)JS引擎執(zhí)行時(shí)GUI線程會(huì)被掛起(相當(dāng)于被凍結(jié)了),GUI更新會(huì)被保存在一個(gè)隊(duì)列中等到JS引擎空閑時(shí)立即被執(zhí)行。JS引擎線程
也稱為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎)
JS引擎線程負(fù)責(zé)解析Javascript腳本,運(yùn)行代碼。
JS引擎一直等待著任務(wù)隊(duì)列中任務(wù)的到來(lái),然后加以處理,一個(gè)Tab頁(yè)(renderer進(jìn)程)中無(wú)論什么時(shí)候都只有一個(gè)JS線程在運(yùn)行JS程序
同樣注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執(zhí)行的時(shí)間過(guò)長(zhǎng),這樣就會(huì)造成頁(yè)面的渲染不連貫,導(dǎo)致頁(yè)面渲染加載阻塞。事件觸發(fā)線程
歸屬于瀏覽器而不是JS引擎,用來(lái)控制事件循環(huán)(可以理解,JS引擎自己都忙不過(guò)來(lái),需要瀏覽器另開線程協(xié)助)
當(dāng)JS引擎執(zhí)行代碼塊如setTimeOut時(shí)(也可來(lái)自瀏覽器內(nèi)核的其他線程,如鼠標(biāo)點(diǎn)擊、AJAX異步請(qǐng)求等),會(huì)將對(duì)應(yīng)任務(wù)添加到事件線程中
當(dāng)對(duì)應(yīng)的事件符合觸發(fā)條件被觸發(fā)時(shí),該線程會(huì)把事件添加到待處理隊(duì)列的隊(duì)尾,等待JS引擎的處理
注意,由于JS的單線程關(guān)系,所以這些待處理隊(duì)列中的事件都得排隊(duì)等待JS引擎處理(當(dāng)JS引擎空閑時(shí)才會(huì)去執(zhí)行)定時(shí)觸發(fā)器線程
傳說(shuō)中的setInterval與setTimeout所在線程
瀏覽器定時(shí)計(jì)數(shù)器并不是由JavaScript引擎計(jì)數(shù)的,(因?yàn)镴avaScript引擎是單線程的, 如果處于阻塞線程狀態(tài)就會(huì)影響記計(jì)時(shí)的準(zhǔn)確)
因此通過(guò)單獨(dú)線程來(lái)計(jì)時(shí)并觸發(fā)定時(shí)(計(jì)時(shí)完畢后,添加到事件隊(duì)列中,等待JS引擎空閑后執(zhí)行)
注意,W3C在HTML標(biāo)準(zhǔn)中規(guī)定,規(guī)定要求setTimeout中低于4ms的時(shí)間間隔算為4ms。異步http請(qǐng)求線程
在XMLHttpRequest在連接后是通過(guò)瀏覽器新開一個(gè)線程請(qǐng)求
將檢測(cè)到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件隊(duì)列中。再由JavaScript引擎執(zhí)行。
上面列出的線程之間,有一個(gè)重要的規(guī)則是:GUI渲染線程與JS引擎線程互斥,那么我們可以得出以下結(jié)論JS阻塞頁(yè)面加載,那么在js運(yùn)行的這段時(shí)間內(nèi),GUI的渲染會(huì)停止,這段時(shí)間內(nèi)的界面交互,DOM的重繪與回流會(huì)停止,會(huì)被保存到待執(zhí)行隊(duì)列中,直到j(luò)s線程空閑,才會(huì)執(zhí)行這些隊(duì)列。
我們用下面的一段代碼和運(yùn)行結(jié)果來(lái)說(shuō)明這個(gè)機(jī)制:
可以看到,一開始網(wǎng)頁(yè)和動(dòng)畫正常運(yùn)行,但是開始執(zhí)行計(jì)算斐波那契數(shù)列后,動(dòng)畫就停止了,頁(yè)面也停止響應(yīng)鼠標(biāo)的click事件了,直到recurFib(40)計(jì)算出結(jié)果后,動(dòng)畫才開始繼續(xù)執(zhí)行,而期間積攢的click事件也在一起被執(zhí)行。這就解釋了GUI渲染線程與JS引擎線程互斥。由于這個(gè)弊端HTML5提出Web Worker標(biāo)準(zhǔn)。
利用Web Worker開啟一個(gè)子線程
Web Worker 有以下幾個(gè)使用注意點(diǎn)。
1.同源限制
分配給 Worker 線程運(yùn)行的腳本文件,必須與主線程的腳本文件同源。
2.DOM 限制
Worker 線程所在的全局對(duì)象,與主線程不一樣,無(wú)法讀取主線程所在網(wǎng)頁(yè)的 DOM 對(duì)象,也無(wú)法使用document、window、parent這些對(duì)象。但是,Worker 線程可以navigator對(duì)象和location對(duì)象。
3.通信聯(lián)系
Worker 線程和主線程不在同一個(gè)上下文環(huán)境,它們不能直接通信,必須通過(guò)消息完成。
4.腳本限制
Worker 線程不能執(zhí)行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 對(duì)象發(fā)出 AJAX 請(qǐng)求。
5.文件限制
Worker 線程無(wú)法讀取本地文件,即不能打開本機(jī)的文件系統(tǒng)(file:),它所加載的腳本,必須來(lái)自網(wǎng)絡(luò)。
創(chuàng)建Worker時(shí),JS引擎向?yàn)g覽器申請(qǐng)開一個(gè)子線程(子線程是瀏覽器開的,完全受主線程控制,而且不能操作DOM)
JS引擎線程與worker線程間通過(guò)特定的方式通信(postMessage API,需要通過(guò)序列化對(duì)象來(lái)與線程交互特定的數(shù)據(jù))。
下面我們用worker的相關(guān)api來(lái)解決上面卡頓的問(wèn)題。
運(yùn)行結(jié)果:
可以看到整個(gè)運(yùn)行過(guò)程動(dòng)畫沒有卡頓,也能響應(yīng)click事件,所以在我們遇到大型計(jì)算的時(shí)候,請(qǐng)單獨(dú)開啟一個(gè)worker子線程來(lái)解決js線程阻塞GUI線程的問(wèn)題。上文中只涉及到一部分worker API。
兼容性
可以看到除了Opera Mini瀏覽器,連IE都能使用了,所以兼容性問(wèn)題不大。
總結(jié)
學(xué)習(xí)如逆水行舟,不進(jìn)則退,前端技術(shù)飛速發(fā)展,如果每天不堅(jiān)持學(xué)習(xí),就會(huì)跟不上,我會(huì)陪著大家,每天堅(jiān)持推送博文,跟大家一同進(jìn)步,希望大家能關(guān)注我,第一時(shí)間收到最新文章。
?
總結(jié)
以上是生活随笔為你收集整理的主进程中发生了一个javascript错误_知道html5 Web Worker标准吗?能实现JavaScript的多线程?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用 Chrome 浏览器插件 Web
- 下一篇: 恢复Windows 10自带的微软正黑字