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