1.進程和線程
- 工廠的資源 -> 系統(tǒng)分配的內(nèi)存(獨立的一塊內(nèi)存)
- 工廠之間的相互獨立 -> 進程之間相互獨立
- 多個工人協(xié)作完成任務(wù) -> 多個線程在進程中協(xié)作完成任務(wù)
- 工廠內(nèi)有一個或多個工人 -> 一個進程由一個或多個線程組成
- 工人之間共享空間 -> 同一進程下的各個線程之間共享程序的內(nèi)存空間(包括代碼段、數(shù)據(jù)集、堆等)
概念:
進程是cpu資源分配的最小單位(是能擁有資源和獨立運行的最小單位)
線程是cpu調(diào)度的最小單位(線程是建立在進程的基礎(chǔ)上的一次程序運行單位,一個進程中可以有多個線程)
瀏覽器是多進程的,包含:
1.Browser進程:瀏覽器的主進程(負責協(xié)調(diào)、主控),只有一個
2.第三方插件進程:每種類型的插件對應(yīng)一個進程,僅當使用該插件時才創(chuàng)建
3.GPU進程:最多一個,用于3D繪制等
4.瀏覽器渲染進程(瀏覽器內(nèi)核)(Renderer進程,內(nèi)部是多線程的):默認每個Tab頁面一個進程,互不影響。
簡單點理解:如果瀏覽器是單進程,那么某個Tab頁崩潰了,就影響了整個瀏覽器,體驗有多差;同理如果是單進程,插件崩潰了也會影響整個瀏覽器;而且多進程還有其它的諸多優(yōu)勢。。。
每新開一個tab頁面就會增加一個進程(你可以在任務(wù)管理器重看),有時如果打開幾個空白的tab頁面它合并成一個進程。而每一個tab頁面進程是由多進程分工合作的:
1.GUI渲染線程
負責渲染瀏覽器界面,解析HTML,CSS,構(gòu)建DOM樹和RenderObject樹,布局和繪制等。
當界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時,該線程就會執(zhí)行
注意,GUI渲染線程與JS引擎線程是互斥的,當JS引擎執(zhí)行時GUI線程會被掛起(相當于被凍結(jié)了),GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執(zhí)行。
2.JS引擎線程
也稱為JS內(nèi)核,負責處理Javascript腳本程序。(例如V8引擎)
JS引擎線程負責解析Javascript腳本,運行代碼。
JS引擎一直等待著任務(wù)隊列中任務(wù)的到來,然后加以處理,一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序
同樣注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞。
3.事件觸發(fā)線程
歸屬于瀏覽器而不是JS引擎,用來控制事件循環(huán)(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協(xié)助)
當JS引擎執(zhí)行代碼塊如setTimeOut時(也可來自瀏覽器內(nèi)核的其他線程,如鼠標點擊、AJAX異步請求等),會將對應(yīng)任務(wù)添加到事件線程中
當對應(yīng)的事件符合觸發(fā)條件被觸發(fā)時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理
注意,由于JS的單線程關(guān)系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執(zhí)行)
4.定時觸發(fā)器線程
傳說中的setInterval與setTimeout所在線程
瀏覽器定時計數(shù)器并不是由JavaScript引擎計數(shù)的,(因為JavaScript引擎是單線程的, 如果處于阻塞線程狀態(tài)就會影響記計時的準確)
因此通過單獨線程來計時并觸發(fā)定時(計時完畢后,添加到事件隊列中,等待JS引擎空閑后執(zhí)行)
注意,W3C在HTML標準中規(guī)定,規(guī)定要求setTimeout中低于4ms的時間間隔算為4ms。
5.異步http請求線程
在XMLHttpRequest在連接后是通過瀏覽器新開一個線程請求
將檢測到狀態(tài)變更時,如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個回調(diào)再放入事件隊列中。再由JavaScript引擎執(zhí)行。

2.事件隊列
在初期許多人會把異步理解成類似多線程的編程模式,其實他們中有著很大的差別,要完全理解異步,就需要了解 JS 的運行核心——事件循環(huán)(event loop)。
2.1 事件循環(huán):【事件隊列】是一個存儲著待執(zhí)行任務(wù)的隊列,其中的任務(wù)嚴格按照時間先后順序執(zhí)行,排在隊頭的任務(wù)將會率先執(zhí)行,而排在隊尾的任務(wù)會最后執(zhí)行。事件隊列每次僅執(zhí)行一個任務(wù),在該任務(wù)執(zhí)行完畢之后,再執(zhí)行下一個任務(wù)?!緢?zhí)行?!縿t是一個類似于函數(shù)調(diào)用棧的運行容器,當執(zhí)行棧為空時,JavaScript引擎便檢查事件隊列,如果不為空的話,事件隊列便將第一個任務(wù)壓入中運行。
[From http://www.php.cn/js-tutorial-369771.html]
2.2 常見異步任務(wù):定時器任務(wù)(setTimeout();setInterval();)、Ajax事件、瀏覽器/用戶行為事件(例如:瀏覽器加載(load)、鼠標單擊click、鼠標滑動/滑過/離開(mouseover、mouseout、mouseleave等)
3.理解JavaScript引擎單線程作業(yè)
所謂單線程,是指在JS引擎中負責解釋和執(zhí)行JavaScript代碼的線程只有一個,也不妨叫它主線程。JavaScript引擎屬于單線程作業(yè),意味著:在同一時間只能執(zhí)行一個代碼塊,這些代碼塊的執(zhí)行就阻塞了異步事件的處理。[From JavaScript忍者秘籍]
JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節(jié)點上添加內(nèi)容,另一個線程刪除了這個節(jié)點,這時瀏覽器應(yīng)該以哪個線程為準?
1 單線程意味著,【所有任務(wù)】都需要排隊,前一個任務(wù)結(jié)束,才會執(zhí)行后一個任務(wù)。如果前一個任務(wù)耗時很長,后一個任務(wù)就不得不一直等著。
2 如果排隊是因為計算量大,CPU忙不過來,倒也算了,但是很多時候CPU是閑著的,因為IO設(shè)備(輸入輸出設(shè)備)很慢(比如Ajax操作從網(wǎng)絡(luò)讀取數(shù)據(jù)),不得不等著結(jié)果出來,再往下執(zhí)行。
3 JavaScript語言的設(shè)計者意識到,這時主線程完全可以不管IO設(shè)備,掛起處于等待中的任務(wù),先運行排在后面的任務(wù)。等到IO設(shè)備返回了結(jié)果,再回過頭,把掛起的任務(wù)繼續(xù)執(zhí)行下去。
4 于是,所有任務(wù)可以分成兩種,一種是同步任務(wù)(synchronous),另一種是異步任務(wù)(asynchronous)。
5 同步任務(wù)指的是,在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù);
6 異步任務(wù)指的是,不進入主線程、而進入"任務(wù)隊列"(task queue)的任務(wù),只有"任務(wù)隊列"通知主線程,某個異步任務(wù)可以執(zhí)行了,該任務(wù)才會進入主線程執(zhí)行。
7 具體來說,異步執(zhí)行的運行機制如下。(同步執(zhí)行也是如此,因為它可以被視為沒有異步任務(wù)的異步執(zhí)行。)
?。?)所有同步任務(wù)都在主線程上執(zhí)行,形成一個執(zhí)行棧(execution context stack)。
(2)主線程之外,還存在一個"任務(wù)隊列"(task queue)。只要異步任務(wù)有了運行結(jié)果,就在"任務(wù)隊列"之中放置一個事件。
(3)一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會讀取"任務(wù)隊列",看看里面有哪些事件。那些對應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進入執(zhí)行棧,開始執(zhí)行。
?。?)主線程不斷重復(fù)上面的第三步。
8 只要主線程空了,就會去讀取"任務(wù)隊列",這就是JavaScript的運行機制。這個過程會不斷重復(fù)。