亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

淺談 JavaScript 運行機制

URLOS / 2748人閱讀

摘要:以多線程的形式,允許單個任務(wù)分成不同的部分進行運行。提供協(xié)調(diào)機制,一方面防止進程之間和線程之間產(chǎn)生沖突,另一方面允許進程之間和線程之間共享資源。主線程會不斷的重復(fù)上訴過程。

眾所周知,js是單線程的,說到線程,我們首先來仔細辨析一下線程和進程的知識。
一、進程與線程

阮一峰老師的一篇文章寫的很好

cpu會給當(dāng)前進程分配資源,進程是資源分配的最小單位,進程的資源會分配給線程使用,線程是CPU調(diào)度的最小單位

1 ——CPU就像是一個大型的工廠一樣。它就像一座工廠,時刻在運行。

2 ——假定工廠的電力有限,一次只能供給一個車間使用。也就是說,一個車間開工的時候,其他車間都必須停工。背后的含義就是,單個CPU一次只能運行一個任務(wù)。

3 ——進程好比是一個工廠的車間,它代表CPU所能處理的單個任務(wù),任意時刻,CPU只能運行一個車間的任務(wù),也就是一個進程,其他進程處于等待狀態(tài)。

4 —— 一個車間里有著許多的工人,他們協(xié)同完成一個任務(wù)。

5 ——單個工人就好比是一個線程,一個進程可以包括多個線程。

6 —— 車間里的空間是可以供工人們共享的,比如許多房間是每個工人都可以進出的。這象征一個進程的內(nèi)存空間是共享的,每個線程都可以使用這些共享內(nèi)存。

7 —— 可是,每間房間的大小不同,有些房間最多只能容納一個人,比如廁所。里面有人的時候,其他人就不能進去了。這代表一個線程使用某些共享內(nèi)存時,其他線程必須等它結(jié)束,才能使用這一塊內(nèi)存。

8 —— 一個防止他人進入的簡單方法,就是門口加一把鎖。先到的人鎖上門,后到的人看到上鎖,就在門口排隊,等鎖打開再進去。這就叫"互斥鎖"(Mutual exclusion,縮寫 Mutex),防止多個線程同時讀寫某一塊內(nèi)存區(qū)域。

9 —— 還有些房間,可以同時容納n個人,比如廚房。也就是說,如果人數(shù)大于n,多出來的人只能在外面等著。這好比某些內(nèi)存區(qū)域,只能供給固定數(shù)目的線程使用。

10 —— 這時的解決方法,就是在門口掛n把鑰匙。進去的人就取一把鑰匙,出來時再把鑰匙掛回原處。后到的人發(fā)現(xiàn)鑰匙架空了,就知道必須在門口排隊等著了。這種做法叫做"信號量"(Semaphore),用來保證多個線程不會互相沖突。

歸納一下:

以多進程的形式,允許多個任務(wù)同時進行。

以多線程的形式,允許單個任務(wù)分成不同的部分進行運行。

提供協(xié)調(diào)機制,一方面防止進程之間和線程之間產(chǎn)生沖突,另一方面允許進程之間和線程之間共享資源。

二、JavaScript是單線程

雖然說js是單線程的,但是瀏覽器并不是單線程的,瀏覽器中的許多異步行為都是由瀏覽器去新開一個線程去解決的,js引擎線程是瀏覽器的線程之一,由于js引擎線程本身是單線程的,所以我們平時說的js單線程指的就是這個了。

瀏覽器還包括很多其他線程,如界面渲染線程,瀏覽器事件觸發(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è)計成單線程的,
JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節(jié)點上添加內(nèi)容,另一個線程刪除了這個節(jié)點,這時瀏覽器應(yīng)該以哪個線程為準(zhǔn)?

所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成了這門語言的核心特征,將來也不會改變。

HTML5中增加了web worker可以去創(chuàng)建一個子線程,但是這個線程仍舊是完全受主線程控制,因此,js的單線程性,依舊是沒有變化的。

三、任務(wù)隊列

單線程就意味著,所有的任務(wù)隊列都需要排隊,前一個任務(wù)結(jié)束,再執(zhí)行后一個任務(wù),如果前一個任務(wù)耗時很長,那么后一個任務(wù)就不得不排著。

如果排隊是因為計算量大,CPU忙不過來,倒也算了,但是很多時候CPU是閑著的,因為IO設(shè)備(輸入輸出設(shè)備)很慢(比如Ajax操作從網(wǎng)絡(luò)讀取數(shù)據(jù)),不得不等著結(jié)果出來,再往下執(zhí)行。

js語言的設(shè)計者也注意到了這個問題,這時候不管IO,掛起來,去執(zhí)行等待中的任務(wù)。等到IO設(shè)備返回了結(jié)果,再回過頭,把掛起的任務(wù)繼續(xù)執(zhí)行下去。

于是這樣就出現(xiàn)了同步任務(wù)異步任務(wù)了。

1、同步任務(wù)

同步任務(wù)是指主線程排隊的任務(wù),只有前一個執(zhí)行完畢,后一個才能執(zhí)行。

2、異步任務(wù)

不進入主線程,而是進入一個任務(wù)隊列,只有任務(wù)隊列,通知了主線程,某一個異步任務(wù)才會執(zhí)行。

下面以AJAX請求為例,來看一下同步和異步的區(qū)別:

異步AJAX:

主線程:“你好,AJAX線程。請你幫我發(fā)個HTTP請求吧,我把請求地址和參數(shù)都給你了?!?p>AJAX線程:“好的,主線程。我馬上去發(fā),但可能要花點兒時間呢,你可以先去忙別的?!?/p>

主線程::“謝謝,你拿到響應(yīng)后告訴我一聲啊?!?/p>

(接著,主線程做其他事情去了。一頓飯的時間后,它收到了響應(yīng)到達的通知。)

同步AJAX:

主線程:“你好,AJAX線程。請你幫我發(fā)個HTTP請求吧,我把請求地址和參數(shù)都給你了?!?p>AJAX線程:“......”

主線程::“喂,AJAX線程,你怎么不說話?”

AJAX線程:“......”

主線程::“喂!喂喂喂!”

AJAX線程:“......”

(一炷香的時間后)

主線程::“喂!求你說句話吧!”

AJAX線程:“主線程,不好意思,我在工作的時候不能說話。你的請求已經(jīng)發(fā)完了,拿到響應(yīng)數(shù)據(jù)了,給你?!?/p>

正是由于JavaScript是單線程的,而異步容易實現(xiàn)非阻塞,所以在JavaScript中對于耗時的操作或者時間不確定的操作,使用異步就成了必然的選擇。異步是這篇文章關(guān)注的重點。

異步過程

所有的同步任務(wù)都再主線程上執(zhí)行,形成一個執(zhí)行棧。

主線程之外還存在一個任務(wù)隊列,一旦任務(wù)隊列中的異步任務(wù)執(zhí)行完畢了,就會產(chǎn)生一個事件。

一旦主線程上的同步任務(wù)執(zhí)行完畢了,那么系統(tǒng)就會讀取任務(wù)隊列,看看有哪些事件。那些事件對應(yīng)的異步任務(wù)就結(jié)束等待狀態(tài),進入執(zhí)行棧,開始執(zhí)行。

主線程會不斷的重復(fù)上訴過程。只要是主線程空了,那么就執(zhí)行任務(wù)隊列中的任務(wù)。

四、事件和回調(diào)函數(shù)

"任務(wù)隊列"是一個事件的隊列(也可以理解成消息的隊列),IO設(shè)備完成一項任務(wù),就在"任務(wù)隊列"中添加一個事件,表示相關(guān)的異步任務(wù)可以進入"執(zhí)行棧"了。主線程讀取"任務(wù)隊列",就是讀取里面有哪些事件。

所謂的回調(diào)函數(shù)就是指被主線程掛起的代碼,異步任務(wù)必須執(zhí)行回調(diào)函數(shù),當(dāng)其產(chǎn)生事件,由主線程調(diào)入執(zhí)行棧后就會執(zhí)行這個回回調(diào)函數(shù)。

任務(wù)隊列就是一個先進先出的一個數(shù)據(jù)結(jié)構(gòu),排在前面的事件,優(yōu)先被主線程調(diào)用,主線程取得過程上是自動的,只有當(dāng)主線程一變?yōu)榭?,那么任?wù)隊列的第一位就會進入主線程,那么就會執(zhí)行對應(yīng)的回調(diào)函數(shù)。

異步函數(shù)
A(args, callbackFn);

一個異步過程包括下面兩個要素:

發(fā)起函數(shù)(或叫注冊函數(shù))A

回調(diào)函數(shù)`callbackFn`

它們都是在主線程上調(diào)用的,其中注冊函數(shù)用來發(fā)起異步過程,回調(diào)函數(shù)用來處理結(jié)果

來一個例子:

DOM點擊事件
var button = document.getElement("#btn");
button.addEventListener("click", function(e) {
    console.log(e);
});

從事件的角度來分析的話,在按鈕上添加了一個鼠標(biāo)點擊的監(jiān)聽器,鼠標(biāo)點擊的時候出發(fā)。

從異步角度分析:

addEventListener函數(shù)就是一個發(fā)起函數(shù),第二個回調(diào)參數(shù)就是回調(diào)函數(shù), 事件觸發(fā)的時候,表示異步任務(wù)執(zhí)行完畢,就產(chǎn)生了事件,將其放入到消息隊列中去,等待主線成的調(diào)用。

這里又出現(xiàn)了一個新的詞匯消息隊列,其實這里面放的就是任務(wù)隊列執(zhí)行完畢后的那些事件通知。等待著主線程的調(diào)用。接下來對其再仔細分析。
五、消息隊列和事件循環(huán)(Event Loop)
未完待續(xù)~~

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/95635.html

相關(guān)文章

  • 淺談小程序運行機制

    摘要:小程序的基礎(chǔ)庫不會被打包在某個小程序的代碼包里邊,它會被提前內(nèi)置在微信客戶端。小程序沒有重啟的概念當(dāng)小程序進入后臺,客戶端會維持一段時間的運行狀態(tài),超過一定時間后目前是分鐘會被微信主動銷毀當(dāng)短時間內(nèi)連續(xù)收到兩次 寫作背景 接觸小程序有一段時間了,總得來說小程序開發(fā)門檻比較低,但其中基本的運行機制和原理還是要懂的。比如我在面試的時候問到一個關(guān)于小程序的問題,問小程序有window對象嗎?...

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

    摘要:將作用域賦值給變量這里的作用域是,而不是將作用域賦值給一個變量閉包返回瀏覽器中內(nèi)存泄漏問題大家都知道,閉包會使變量駐留在內(nèi)存中,這也就導(dǎo)致了內(nèi)存泄漏。 上一章我們講了匿名函數(shù)和閉包,這次我們來談?wù)勯]包中作用域this的問題。 大家都知道,this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的,如果this在全局就是[object window],如果在對象內(nèi)部就是指向這個對象,而閉包卻是在運行...

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

    摘要:事實上,瀏覽器內(nèi)部的運行機制是,先將通信內(nèi)容串行化,然后把串行化后的字符串發(fā)給子線程,后者再將它還原。當(dāng)一個的文檔列表中的任何一個對象都是處于完全活動狀態(tài)的時候,這個會被稱之為需要激活線程。 瀏覽器中的Web Worker 背景介紹 我們都知道JavaScript這個語言在執(zhí)行的時候是采用單線程進行執(zhí)行的,也就是說在同一時間只能做一件事,這也和這門語言有很大的關(guān)系,采用同步執(zhí)行的方式進...

    Tecode 評論0 收藏0

發(fā)表評論

0條評論

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