摘要:以多線程的形式,允許單個(gè)任務(wù)分成不同的部分進(jìn)行運(yùn)行。提供協(xié)調(diào)機(jī)制,一方面防止進(jìn)程之間和線程之間產(chǎn)生沖突,另一方面允許進(jìn)程之間和線程之間共享資源。主線程會不斷的重復(fù)上訴過程。
眾所周知,js是單線程的,說到線程,我們首先來仔細(xì)辨析一下線程和進(jìn)程的知識。一、進(jìn)程與線程
阮一峰老師的一篇文章寫的很好
cpu會給當(dāng)前進(jìn)程分配資源,進(jìn)程是資源分配的最小單位,進(jìn)程的資源會分配給線程使用,線程是CPU調(diào)度的最小單位
1 ——CPU就像是一個(gè)大型的工廠一樣。它就像一座工廠,時(shí)刻在運(yùn)行。
2 ——假定工廠的電力有限,一次只能供給一個(gè)車間使用。也就是說,一個(gè)車間開工的時(shí)候,其他車間都必須停工。背后的含義就是,單個(gè)CPU一次只能運(yùn)行一個(gè)任務(wù)。
3 ——進(jìn)程好比是一個(gè)工廠的車間,它代表CPU所能處理的單個(gè)任務(wù),任意時(shí)刻,CPU只能運(yùn)行一個(gè)車間的任務(wù),也就是一個(gè)進(jìn)程,其他進(jìn)程處于等待狀態(tài)。
4 —— 一個(gè)車間里有著許多的工人,他們協(xié)同完成一個(gè)任務(wù)。
5 ——單個(gè)工人就好比是一個(gè)線程,一個(gè)進(jìn)程可以包括多個(gè)線程。
6 —— 車間里的空間是可以供工人們共享的,比如許多房間是每個(gè)工人都可以進(jìn)出的。這象征一個(gè)進(jìn)程的內(nèi)存空間是共享的,每個(gè)線程都可以使用這些共享內(nèi)存。
7 —— 可是,每間房間的大小不同,有些房間最多只能容納一個(gè)人,比如廁所。里面有人的時(shí)候,其他人就不能進(jìn)去了。這代表一個(gè)線程使用某些共享內(nèi)存時(shí),其他線程必須等它結(jié)束,才能使用這一塊內(nèi)存。
8 —— 一個(gè)防止他人進(jìn)入的簡單方法,就是門口加一把鎖。先到的人鎖上門,后到的人看到上鎖,就在門口排隊(duì),等鎖打開再進(jìn)去。這就叫"互斥鎖"(Mutual exclusion,縮寫 Mutex),防止多個(gè)線程同時(shí)讀寫某一塊內(nèi)存區(qū)域。
9 —— 還有些房間,可以同時(shí)容納n個(gè)人,比如廚房。也就是說,如果人數(shù)大于n,多出來的人只能在外面等著。這好比某些內(nèi)存區(qū)域,只能供給固定數(shù)目的線程使用。
10 —— 這時(shí)的解決方法,就是在門口掛n把鑰匙。進(jìn)去的人就取一把鑰匙,出來時(shí)再把鑰匙掛回原處。后到的人發(fā)現(xiàn)鑰匙架空了,就知道必須在門口排隊(duì)等著了。這種做法叫做"信號量"(Semaphore),用來保證多個(gè)線程不會互相沖突。
歸納一下:
以多進(jìn)程的形式,允許多個(gè)任務(wù)同時(shí)進(jìn)行。
以多線程的形式,允許單個(gè)任務(wù)分成不同的部分進(jìn)行運(yùn)行。
提供協(xié)調(diào)機(jī)制,一方面防止進(jìn)程之間和線程之間產(chǎn)生沖突,另一方面允許進(jìn)程之間和線程之間共享資源。
二、JavaScript是單線程雖然說js是單線程的,但是瀏覽器并不是單線程的,瀏覽器中的許多異步行為都是由瀏覽器去新開一個(gè)線程去解決的,js引擎線程是瀏覽器的線程之一,由于js引擎線程本身是單線程的,所以我們平時(shí)說的js單線程指的就是這個(gè)了。
瀏覽器還包括很多其他線程,如界面渲染線程,瀏覽器事件觸發(fā)線程,Http請求線程等。
1、證明js是單線程的// 證明js是單線程的 function foo() { console.log("first"); setTimeout(( function(){ console.log( "second" ); }),5); } for (var i = 0; i < 1000000; i++) { foo(); } // 執(zhí)行結(jié)果會首先全部輸出first,然后全部輸出second;盡管中間的執(zhí)行會超過5ms。2.js為什么要設(shè)計(jì)成單線程的,
JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JavaScript同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)DOM節(jié)點(diǎn)上添加內(nèi)容,另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器應(yīng)該以哪個(gè)線程為準(zhǔn)?
所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成了這門語言的核心特征,將來也不會改變。
HTML5中增加了web worker可以去創(chuàng)建一個(gè)子線程,但是這個(gè)線程仍舊是完全受主線程控制,因此,js的單線程性,依舊是沒有變化的。
三、任務(wù)隊(duì)列單線程就意味著,所有的任務(wù)隊(duì)列都需要排隊(duì),前一個(gè)任務(wù)結(jié)束,再執(zhí)行后一個(gè)任務(wù),如果前一個(gè)任務(wù)耗時(shí)很長,那么后一個(gè)任務(wù)就不得不排著。
如果排隊(duì)是因?yàn)橛?jì)算量大,CPU忙不過來,倒也算了,但是很多時(shí)候CPU是閑著的,因?yàn)镮O設(shè)備(輸入輸出設(shè)備)很慢(比如Ajax操作從網(wǎng)絡(luò)讀取數(shù)據(jù)),不得不等著結(jié)果出來,再往下執(zhí)行。
js語言的設(shè)計(jì)者也注意到了這個(gè)問題,這時(shí)候不管IO,掛起來,去執(zhí)行等待中的任務(wù)。等到IO設(shè)備返回了結(jié)果,再回過頭,把掛起的任務(wù)繼續(xù)執(zhí)行下去。
于是這樣就出現(xiàn)了同步任務(wù)與異步任務(wù)了。
1、同步任務(wù)同步任務(wù)是指主線程排隊(duì)的任務(wù),只有前一個(gè)執(zhí)行完畢,后一個(gè)才能執(zhí)行。
2、異步任務(wù)不進(jìn)入主線程,而是進(jìn)入一個(gè)任務(wù)隊(duì)列,只有任務(wù)隊(duì)列,通知了主線程,某一個(gè)異步任務(wù)才會執(zhí)行。
下面以AJAX請求為例,來看一下同步和異步的區(qū)別:
異步AJAX:
主線程:“你好,AJAX線程。請你幫我發(fā)個(gè)HTTP請求吧,我把請求地址和參數(shù)都給你了?!?p>AJAX線程:“好的,主線程。我馬上去發(fā),但可能要花點(diǎn)兒時(shí)間呢,你可以先去忙別的?!?/p>主線程::“謝謝,你拿到響應(yīng)后告訴我一聲啊。”
(接著,主線程做其他事情去了。一頓飯的時(shí)間后,它收到了響應(yīng)到達(dá)的通知。)
同步AJAX:
主線程:“你好,AJAX線程。請你幫我發(fā)個(gè)HTTP請求吧,我把請求地址和參數(shù)都給你了。”AJAX線程:“......”
主線程::“喂,AJAX線程,你怎么不說話?”
AJAX線程:“......”
主線程::“喂!喂喂喂!”
AJAX線程:“......”
(一炷香的時(shí)間后)
主線程::“喂!求你說句話吧!”
AJAX線程:“主線程,不好意思,我在工作的時(shí)候不能說話。你的請求已經(jīng)發(fā)完了,拿到響應(yīng)數(shù)據(jù)了,給你。”
正是由于JavaScript是單線程的,而異步容易實(shí)現(xiàn)非阻塞,所以在JavaScript中對于耗時(shí)的操作或者時(shí)間不確定的操作,使用異步就成了必然的選擇。異步是這篇文章關(guān)注的重點(diǎn)。
異步過程
所有的同步任務(wù)都再主線程上執(zhí)行,形成一個(gè)執(zhí)行棧。
主線程之外還存在一個(gè)任務(wù)隊(duì)列,一旦任務(wù)隊(duì)列中的異步任務(wù)執(zhí)行完畢了,就會產(chǎn)生一個(gè)事件。
一旦主線程上的同步任務(wù)執(zhí)行完畢了,那么系統(tǒng)就會讀取任務(wù)隊(duì)列,看看有哪些事件。那些事件對應(yīng)的異步任務(wù)就結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
主線程會不斷的重復(fù)上訴過程。只要是主線程空了,那么就執(zhí)行任務(wù)隊(duì)列中的任務(wù)。
四、事件和回調(diào)函數(shù)"任務(wù)隊(duì)列"是一個(gè)事件的隊(duì)列(也可以理解成消息的隊(duì)列),IO設(shè)備完成一項(xiàng)任務(wù),就在"任務(wù)隊(duì)列"中添加一個(gè)事件,表示相關(guān)的異步任務(wù)可以進(jìn)入"執(zhí)行棧"了。主線程讀取"任務(wù)隊(duì)列",就是讀取里面有哪些事件。
所謂的回調(diào)函數(shù)就是指被主線程掛起的代碼,異步任務(wù)必須執(zhí)行回調(diào)函數(shù),當(dāng)其產(chǎn)生事件,由主線程調(diào)入執(zhí)行棧后就會執(zhí)行這個(gè)回回調(diào)函數(shù)。
任務(wù)隊(duì)列就是一個(gè)先進(jìn)先出的一個(gè)數(shù)據(jù)結(jié)構(gòu),排在前面的事件,優(yōu)先被主線程調(diào)用,主線程取得過程上是自動的,只有當(dāng)主線程一變?yōu)榭?,那么任?wù)隊(duì)列的第一位就會進(jìn)入主線程,那么就會執(zhí)行對應(yīng)的回調(diào)函數(shù)。
異步函數(shù)
A(args, callbackFn);
一個(gè)異步過程包括下面兩個(gè)要素:
發(fā)起函數(shù)(或叫注冊函數(shù))A
回調(diào)函數(shù)`callbackFn`
它們都是在主線程上調(diào)用的,其中注冊函數(shù)用來發(fā)起異步過程,回調(diào)函數(shù)用來處理結(jié)果
來一個(gè)例子:
DOM點(diǎn)擊事件
var button = document.getElement("#btn"); button.addEventListener("click", function(e) { console.log(e); });
從事件的角度來分析的話,在按鈕上添加了一個(gè)鼠標(biāo)點(diǎn)擊的監(jiān)聽器,鼠標(biāo)點(diǎn)擊的時(shí)候出發(fā)。
從異步角度分析:
addEventListener函數(shù)就是一個(gè)發(fā)起函數(shù),第二個(gè)回調(diào)參數(shù)就是回調(diào)函數(shù), 事件觸發(fā)的時(shí)候,表示異步任務(wù)執(zhí)行完畢,就產(chǎn)生了事件,將其放入到消息隊(duì)列中去,等待主線成的調(diào)用。
這里又出現(xiàn)了一個(gè)新的詞匯消息隊(duì)列,其實(shí)這里面放的就是任務(wù)隊(duì)列執(zhí)行完畢后的那些事件通知。等待著主線程的調(diào)用。接下來對其再仔細(xì)分析。五、消息隊(duì)列和事件循環(huán)(Event Loop)
未完待續(xù)~~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/95635.html
摘要:小程序的基礎(chǔ)庫不會被打包在某個(gè)小程序的代碼包里邊,它會被提前內(nèi)置在微信客戶端。小程序沒有重啟的概念當(dāng)小程序進(jìn)入后臺,客戶端會維持一段時(shí)間的運(yùn)行狀態(tài),超過一定時(shí)間后目前是分鐘會被微信主動銷毀當(dāng)短時(shí)間內(nèi)連續(xù)收到兩次 寫作背景 接觸小程序有一段時(shí)間了,總得來說小程序開發(fā)門檻比較低,但其中基本的運(yùn)行機(jī)制和原理還是要懂的。比如我在面試的時(shí)候問到一個(gè)關(guān)于小程序的問題,問小程序有window對象嗎?...
摘要:將作用域賦值給變量這里的作用域是,而不是將作用域賦值給一個(gè)變量閉包返回瀏覽器中內(nèi)存泄漏問題大家都知道,閉包會使變量駐留在內(nèi)存中,這也就導(dǎo)致了內(nèi)存泄漏。 上一章我們講了匿名函數(shù)和閉包,這次我們來談?wù)勯]包中作用域this的問題。 大家都知道,this對象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境綁定的,如果this在全局就是[object window],如果在對象內(nèi)部就是指向這個(gè)對象,而閉包卻是在運(yùn)行...
摘要:事實(shí)上,瀏覽器內(nèi)部的運(yùn)行機(jī)制是,先將通信內(nèi)容串行化,然后把串行化后的字符串發(fā)給子線程,后者再將它還原。當(dāng)一個(gè)的文檔列表中的任何一個(gè)對象都是處于完全活動狀態(tài)的時(shí)候,這個(gè)會被稱之為需要激活線程。 瀏覽器中的Web Worker 背景介紹 我們都知道JavaScript這個(gè)語言在執(zhí)行的時(shí)候是采用單線程進(jìn)行執(zhí)行的,也就是說在同一時(shí)間只能做一件事,這也和這門語言有很大的關(guān)系,采用同步執(zhí)行的方式進(jìn)...
閱讀 1263·2021-11-08 13:25
閱讀 1452·2021-10-13 09:40
閱讀 2783·2021-09-28 09:35
閱讀 748·2021-09-23 11:54
閱讀 1139·2021-09-02 15:11
閱讀 2446·2019-08-30 13:18
閱讀 1681·2019-08-30 12:51
閱讀 2697·2019-08-29 18:39