摘要:的單線程,與它的用途有關(guān)。為了利用多核的計(jì)算能力,提出標(biāo)準(zhǔn),允許腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作。
一、進(jìn)程與線程 1.進(jìn)程
進(jìn)程是指程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間,可以通過windows任務(wù)管理器查看進(jìn)程(如下圖)。同一個時(shí)間里,同一個計(jì)算機(jī)系統(tǒng)中允許兩個或兩個以上的進(jìn)程處于并行狀態(tài),這是多進(jìn)程。比如電腦同時(shí)運(yùn)行微信,QQ,以及各種瀏覽器等。瀏覽器運(yùn)行是有些是單進(jìn)程,如firefox和老版IE,有些是多進(jìn)程,如chrome和新版IE。
2.線程有些進(jìn)程還不止同時(shí)干一件事,比如Word,它可以同時(shí)進(jìn)行打字、拼寫檢查、打印等事情。在一個進(jìn)程內(nèi)部,要同時(shí)干多件事,就需要同時(shí)運(yùn)行多個“子任務(wù)”,我們把進(jìn)程內(nèi)的這些“子任務(wù)”稱為線程(Thread)。
線程是指CPU的基本調(diào)度單位,是程序執(zhí)行的一個完整流程,是進(jìn)程內(nèi)的一個獨(dú)立執(zhí)行單元。多線程是指在一個進(jìn)程內(nèi), 同時(shí)有多個線程運(yùn)行。瀏覽器運(yùn)行是多線程。比如用瀏覽器一邊下載,一邊聽歌,一邊看視頻。另外我們需要知道JavaScript語言的一大特點(diǎn)就是單線程,為了利用多核CPU的計(jì)算能力,HTML5提出Web Worker標(biāo)準(zhǔn),允許JavaScript腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)。
由于每個進(jìn)程至少要干一件事,所以,一個進(jìn)程至少有一個線程。當(dāng)然,像Word這種復(fù)雜的進(jìn)程可以有多個線程,多個線程可以同時(shí)執(zhí)行,多線程的執(zhí)行方式和多進(jìn)程是一樣的,也是由操作系統(tǒng)在多個線程之間快速切換,讓每個線程都短暫地交替運(yùn)行,看起來就像同時(shí)執(zhí)行一樣。當(dāng)然,真正地同時(shí)執(zhí)行多線程需要多核CPU才可能實(shí)現(xiàn)。
3.進(jìn)程與線程應(yīng)用程序必須運(yùn)行在某個進(jìn)程的某個線程上
一個進(jìn)程中至少有一個運(yùn)行的線程: 主線程, 進(jìn)程啟動后自動創(chuàng)建
一個進(jìn)程中如果同時(shí)運(yùn)行多個線程, 那這個程序是多線程運(yùn)行的
一個進(jìn)程的內(nèi)存空間是共享的,每個線程都可以使用這些共享內(nèi)存。
多個進(jìn)程之間的數(shù)據(jù)是不能直接共享的
4.單線程與多線程的優(yōu)缺點(diǎn)?單線程的優(yōu)點(diǎn):順序編程簡單易懂
單線程的缺點(diǎn):效率低
多線程的優(yōu)點(diǎn):能有效提升CPU的利用率
多線程的缺點(diǎn):
創(chuàng)建多線程開銷
線程間切換開銷
死鎖與狀態(tài)同步問題
二、瀏覽器內(nèi)核瀏覽器的內(nèi)核是指支持瀏覽器運(yùn)行的最核心的程序,分為兩個部分的,一是渲染引擎,另一個是JS引擎?,F(xiàn)在JS引擎比較獨(dú)立,內(nèi)核更加傾向于說渲染引擎。
1.不同的瀏覽器可能不太一樣Chrome, Safari: webkit
firefox: Gecko
IE: Trident
360,搜狗等國內(nèi)瀏覽器: Trident + webkit
2.內(nèi)核由很多模塊組成html,css文檔解析模塊 : 負(fù)責(zé)頁面文本的解析
dom/css模塊 : 負(fù)責(zé)dom/css在內(nèi)存中的相關(guān)處理
布局和渲染模塊 : 負(fù)責(zé)頁面的布局和效果的繪制
定時(shí)器模塊 : 負(fù)責(zé)定時(shí)器的管理
網(wǎng)絡(luò)請求模塊 : 負(fù)責(zé)服務(wù)器請求(常規(guī)/Ajax)
事件響應(yīng)模塊 : 負(fù)責(zé)事件的管理
三、定時(shí)器引發(fā)的思考 1. 定時(shí)器真是定時(shí)執(zhí)行的嗎?我們先來看個例子,試問定時(shí)器會保證200ms后執(zhí)行嗎?
document.getElementById("btn").onclick = function () { var start = Date.now() console.log("啟動定時(shí)器前...") setTimeout(function () { console.log("定時(shí)器執(zhí)行了", Date.now() - start) }, 200) console.log("啟動定時(shí)器后...") // 做一個長時(shí)間的工作 for (var i = 0; i < 1000000000; i++) { } }
事實(shí)上,經(jīng)過了625ms后定時(shí)器才執(zhí)行。定時(shí)器并不能保證真正定時(shí)執(zhí)行,一般會延遲一丁點(diǎn),也有可能延遲很長時(shí)間(比如上面的例子)
定時(shí)器回調(diào)函數(shù)在主線程執(zhí)行的, 具體實(shí)現(xiàn)方式下文會介紹。
四、瀏覽器的事件循環(huán)(輪詢)模型 1. 為什么JavaScript是單線程JavaScript語言的一大特點(diǎn)就是單線程,也就是說,同一個時(shí)間只能做一件事。那么,為什么JavaScript不能有多個線程呢?這樣能提高效率啊。
JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JavaScript同時(shí)有兩個線程,一個線程在某個DOM節(jié)點(diǎn)上添加內(nèi)容,另一個線程刪除了這個節(jié)點(diǎn),這時(shí)瀏覽器應(yīng)該以哪個線程為準(zhǔn)?
所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成了這門語言的核心特征,將來也不會改變。
為了利用多核CPU的計(jì)算能力,HTML5提出Web Worker標(biāo)準(zhǔn),允許JavaScript腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)。
JavaScript中所有任務(wù)可以分成兩種,一種是同步任務(wù),另一種是異步任務(wù)(如各種瀏覽器事件、定時(shí)器和Ajax等)。同步任務(wù)指的是,在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù);異步任務(wù)指的是,不進(jìn)入主線程、而進(jìn)入"任務(wù)隊(duì)列"(task queue)的任務(wù),只有"任務(wù)隊(duì)列"通知主線程,某個異步任務(wù)可以執(zhí)行了,該任務(wù)才會進(jìn)入主線程執(zhí)行。
具體來說,異步執(zhí)行的運(yùn)行機(jī)制如下。(同步執(zhí)行也是如此,因?yàn)樗梢员灰暈闆]有異步任務(wù)的異步執(zhí)行。)
(1)所有同步任務(wù)都在主線程上執(zhí)行,形成一個執(zhí)行棧(execution context stack)。
(2)主線程之外,還存在一個"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個事件。
(3)一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會讀取"任務(wù)隊(duì)列",看看里面有哪些事件。那些對應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
(4)主線程不斷重復(fù)上面的第三步
主線程從"任務(wù)隊(duì)列"中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))
下面這個例子很好闡釋事件循環(huán):
setTimeout(function () { console.log("timeout 2222") alert("22222222") }, 2000) setTimeout(function () { console.log("timeout 1111") alert("1111111") }, 1000) setTimeout(function () { console.log("timeout() 00000") }, 0)//當(dāng)指定的值小于 4 毫秒,則增加到 4ms(4ms 是 HTML5 標(biāo)準(zhǔn)指定的,對于 2010 年及之前的瀏覽器則是 10ms) function fn() { console.log("fn()") } fn() console.log("alert()之前") alert("------") //暫停當(dāng)前主線程的執(zhí)行, 同時(shí)暫停計(jì)時(shí), 點(diǎn)擊確定后, 恢復(fù)程序執(zhí)行和計(jì)時(shí) console.log("alert()之后")
有兩點(diǎn)我們需要注意下:
定時(shí)器零延遲(setTimeout(func, 0))并不是意味著回調(diào)函數(shù)立刻執(zhí)行。至少4ms,才會執(zhí)行回調(diào)函數(shù)。它取決于主線程當(dāng)前是否空閑與“任務(wù)隊(duì)列”里其前面正在等待的任務(wù)。
只有在到達(dá)指定時(shí)間時(shí),定時(shí)器就會將相應(yīng)回調(diào)函數(shù)插入“任務(wù)隊(duì)列”尾部
總結(jié):異步任務(wù)(各種瀏覽器事件、定時(shí)器和Ajax等)都是先添加到“任務(wù)隊(duì)列”(定時(shí)器則到達(dá)其指定參數(shù)時(shí))。當(dāng) Stack 棧(JavaScript 主線程)為空時(shí),就會讀取 Queue 隊(duì)列(任務(wù)隊(duì)列)的第一個任務(wù)(隊(duì)首),最后執(zhí)行。
五、H5 Web Workers(多線程) 1. Web Workers的作用正如上面所提到,JavaScript是單線程。當(dāng)一個頁面加載一個復(fù)雜運(yùn)算的 js 文件時(shí),用戶界面可能會短暫地“凍結(jié)”,不能再做其他操作。比如下面這個例子:
很顯然遇到這種頁面堵塞情況,很影響用戶體驗(yàn)的,有沒有啥辦法可以改進(jìn)這種情形?----Web Worker就應(yīng)運(yùn)而生了!
Web Worker 的作用,就是為 JavaScript 創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker 線程,將一些任務(wù)分配給后者運(yùn)行。在主線程運(yùn)行的同時(shí),Worker 線程在后臺運(yùn)行,兩者互不干擾。等到 Worker 線程完成計(jì)算任務(wù),再把結(jié)果返回給主線程。這樣的好處是,一些計(jì)算密集型或高延遲的任務(wù),被 Worker 線程負(fù)擔(dān)了,主線程(通常負(fù)責(zé) UI 交互)就會很流暢,不會被阻塞或拖慢。其原理圖如下:
2. Web Workers的基本使用主線程
首先主線程采用new命令,調(diào)用Worker()構(gòu)造函數(shù),新建一個 Worker 線程
var worker = new Worker("work.js");
然后主線程調(diào)用worker.postMessage()方法,向 Worker 發(fā)消息。
接著,主線程通過worker.onmessage指定監(jiān)聽函數(shù),接收子線程發(fā)回來的消息。
var input = document.getElementById("number") document.getElementById("btn").onclick = function () { var number = input.value //創(chuàng)建一個Worker對象 var worker = new Worker("worker.js") // 綁定接收消息的監(jiān)聽 worker.onmessage = function (event) { console.log("主線程接收分線程返回的數(shù)據(jù): "+event.data) alert(event.data) } // 向分線程發(fā)送消息 worker.postMessage(number) console.log("主線程向分線程發(fā)送數(shù)據(jù): "+number) } console.log(this) // window
Worker 線程
Worker 線程內(nèi)部需要有一個監(jiān)聽函數(shù),監(jiān)聽message事件。
通過 postMessage(data) 方法來向主線程發(fā)送數(shù)據(jù)。
//worker.js文件 function fibonacci(n) { return n<=2 ? 1 : fibonacci(n-1) + fibonacci(n-2) //遞歸調(diào)用 } console.log(this)//[object DedicatedWorkerGlobalScope] this.onmessage = function (event) { var number = event.data console.log("分線程接收到主線程發(fā)送的數(shù)據(jù): "+number) //計(jì)算 var result = fibonacci(number) postMessage(result) console.log("分線程向主線程返回?cái)?shù)據(jù): "+result) // alert(result) alert是window的方法, 在分線程不能調(diào)用 // 分線程中的全局對象不再是window, 所以在分線程中不可能更新界面 }
這樣當(dāng)分線程在計(jì)算時(shí),用戶界面還可以操作,而且更早拿到計(jì)算后數(shù)據(jù),響應(yīng)速度更快了。
不能跨域加載JS
worker內(nèi)代碼不能訪問DOM(更新UI)
不是每個瀏覽器都支持這個新特性(本文例子只能在Firefox瀏覽器上運(yùn)行,chrome不支持)
如果需要源代碼,請猛戳Web Workers
如果覺得文章對你有些許幫助,歡迎在我的GitHub博客點(diǎn)贊和關(guān)注,感激不盡!
參考文章 進(jìn)程和線程 進(jìn)程與線程的一個簡單解釋 關(guān)于JavaScript單線程的一些事 JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop Web Worker 是什么鬼? Web Worker 使用教程文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/53087.html
摘要:異步任務(wù)必須指定回調(diào)函數(shù),當(dāng)異步任務(wù)從任務(wù)隊(duì)列回到執(zhí)行棧,回調(diào)函數(shù)就會執(zhí)行。事件循環(huán)主線程從任務(wù)隊(duì)列中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運(yùn)行機(jī)制又稱為。事件循環(huán)事件循環(huán)是指主線程重復(fù)從消息隊(duì)列中取消息執(zhí)行的過程。 參考鏈接:這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制https://zhuanlan.zhihu.com/p/...從瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制...
摘要:線程機(jī)制與事件機(jī)制一進(jìn)程與線程進(jìn)程程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間。事件響應(yīng)模塊負(fù)責(zé)事件的管理。當(dāng)事件發(fā)生時(shí)管理模塊會將回調(diào)函數(shù)及其數(shù)據(jù)添加到回調(diào)列隊(duì)中。但是子線程完全受主線程控制,且不得操作。向另一個線程發(fā)送消息。 JavaScript線程機(jī)制與事件機(jī)制 一、進(jìn)程與線程 進(jìn)程(process) 程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間。 可以通過windows任務(wù)管理器查...
摘要:的單線程,與它的用途有關(guān)。為了利用多核的計(jì)算能力,提出標(biāo)準(zhǔn),允許腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作。 showImg(https://segmentfault.com/img/remote/1460000016649971?w=1481&h=876); 一、進(jìn)程與線程 1.進(jìn)程 進(jìn)程是指程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間,可以通過windows任務(wù)管理器查看...
摘要:的單線程,與它的用途有關(guān)。為了利用多核的計(jì)算能力,提出標(biāo)準(zhǔn),允許腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作。 showImg(https://segmentfault.com/img/remote/1460000016649971?w=1481&h=876); 一、進(jìn)程與線程 1.進(jìn)程 進(jìn)程是指程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間,可以通過windows任務(wù)管理器查看...
摘要:的單線程,與它的用途有關(guān)。為了利用多核的計(jì)算能力,提出標(biāo)準(zhǔn),允許腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作。 showImg(https://segmentfault.com/img/remote/1460000016649971?w=1481&h=876); 一、進(jìn)程與線程 1.進(jìn)程 進(jìn)程是指程序的一次執(zhí)行,它占有一片獨(dú)有的內(nèi)存空間,可以通過windows任務(wù)管理器查看...
閱讀 1449·2021-11-22 13:54
閱讀 4364·2021-09-22 15:56
閱讀 1822·2021-09-03 10:30
閱讀 1321·2021-09-03 10:30
閱讀 2089·2019-08-30 15:55
閱讀 1857·2019-08-30 14:13
閱讀 2063·2019-08-29 15:19
閱讀 2362·2019-08-28 18:13