成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

淺談 JavaScript 運(yùn)行機(jī)制

URLOS / 2690人閱讀

摘要:以多線程的形式,允許單個(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

相關(guān)文章

  • 淺談小程序運(yùn)行機(jī)制

    摘要:小程序的基礎(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對象嗎?...

    Caicloud 評論0 收藏0
  • 淺談Javascript閉包中作用域及內(nèi)存泄漏問題

    摘要:將作用域賦值給變量這里的作用域是,而不是將作用域賦值給一個(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)行...

    source 評論0 收藏0
  • 淺談HTML5 Web Worker

    摘要:事實(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)...

    Tecode 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<