摘要:當主線程開始執行異步任務,實際就是執行對應的回調函數。異步任務必須指定回調函數。所以注意的是,只是將事件插入了任務隊列,必須等到當前代碼執行棧執行完,主線程才會去執行它指定的回調函數。
最近本人對于js的運行機制,特別是異步,還有回調函數感覺很亂,于是參考了很多有用的博客(博客原文地址會在文末給出),整理如下:
js單線程我們都知道,Javascript語言的執行環境是"單線程"(single thread)。也就是說,瀏覽器只分配給js一個主線程用來執行任務即函數,但是每次只能執行一個任務,只有等到當前任務執行完成后,才執行后面的任務,這些任務形成一個任務隊列排隊等候執行,這一點和我們日常的排隊很像,譬如排隊買奶茶,只有等到前面一個人買完奶茶付完錢,排在他后面的人才可以買奶茶。但是,當前面一個任務很耗時時,后面的任務就不得不等著,這時候整個程序的執行效率就會下降,就像我們平時遇到的瀏覽器無響應即頁面假死往往是因為某段js代碼長時間運行如死循環,導致頁面卡死,后面的任務無法執行。
講到js的單線程,就不得不來了解一下瀏覽器
瀏覽器多線程
如圖,瀏覽器是一個多線程的執行環境,在瀏覽器的內核中分配了多個線程,其中瀏覽器常駐三大線程: js引擎線程,GUI渲染線程,瀏覽器事件觸發線程。最主要的線程之一即是js引擎的線程。由于這三個線程同時要訪問DOM樹,所以為了線程安全,瀏覽器內部需要做互斥即當JS引擎在執行代碼的時候,界面渲染和事件響應兩個線程是被暫停的。而所以當JS出現死循環,瀏覽器無法響應點擊,也無法更新界面。
前面說到,前端會有一些任務十分耗時,而由于js是單線程使用會降低執行效率,這些耗時的任務如網絡請求,定時器和事件監聽。所以,瀏覽器為這些耗時任務開辟了另外的線程,主要包括http請求線程,瀏覽器定時觸發器,瀏覽器事件觸發線程,這些任務是異步的(見圖)。(詳細過程見此博文,博主講得很好~ 個人建議必須看一看哦~)
任務隊列說回剛剛的js單線程,為了不讓前面的耗時任務導致的問題出現,js的設計者把js的任務分為同步任務和異步任務。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行后一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。如我們剛剛所講到的瀏覽器為網絡請求開辟的http請求線程就是異步任務。
具體來說,異步執行的運行機制如下。(同步執行也是如此,因為它可以被視為沒有異步任務的異步執行。)
(1)所有同步任務都在主線程上執行,形成一個[執行棧]。
(2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。
(3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。
(4)主線程不斷重復上面的第三步。
(參考與阮一峰老師的博文JavaScript 運行機制詳解:再談Event Loop)
回調函數有了以上了解我們可以知道,主線程內的同步任務執行完畢后,就會執行排在任務隊列第一位的異步任務,這個過程不斷重復。
當主線程開始執行異步任務,實際就是執行對應的回調函數。
我們來看一下例子:
setTimeout(function(){ console.log("Hello"); },10);
執行這段代碼,瀏覽器異步執行計時操作(注意這里的瀏覽器模型定時計數器并不是由JavaScript引擎計數的),當10ms到了之后,就會觸發定時事件,這時就會把其中的回調函數放到任務隊列中,所以當主線程空閑時在任務隊列中“讀取”并且執行的就是回調函數。
異步任務必須指定回調函數。
Event Loop主線程從"任務隊列"中讀取事件,這個過程是循環不斷的,所以整個的這種運行機制又稱為Event Loop(事件循環)。
如圖,WebAPIs就是js線程外部的api如我們剛剛所說瀏覽器為異步任務所開辟的線程。而任務隊列就是callbackqueue,我們知道任務隊列中其實就是各種異步任務的回調函數,從callbackqueue的直譯“回調隊列”也可看出。而heap堆和stack棧組成了js的主線程,當stack中的函數執行完成后,就會在callbackqueue中尋找下一個任務并把它推入棧,這個尋找的過程就叫event loop(事件循環)。
看了上面你是不是對js的運行機制有了了解呢~
我們把學會的知識來用一用:
說起js的異步,很多人第一反應是Ajax,但其實js中最基礎的異步就是setTimeout/setInterval。(小伙伴可不要把定時器忘了哦:))
我們以setTimeout為例,setTimeout接受兩個參數,第一個是回調函數,第二個是推遲執行的毫秒數。
我們看看例子:
setTimeout(function(){ console.log(0); },0) console.log(1); // 1 // 0
是不是以為打印的順序是0,1?但大家注意哦,這時候瀏覽器打印的順序是1,0。大家可能疑問了,setTimeout中設置的推遲執行的毫秒數是0呀,不就是立即執行的意思嗎。大家還記得剛剛我們說了當有耗時任務時,會把它放在任務隊列中等待主線程空閑然后再執行,實際在執行程序的時候,瀏覽器會默認setTimeout以及ajax請求這一類的方法都是耗時程序(盡管可能不耗時),也就是上面說過的瀏覽器會為其異步開辟線程。所以此時的setTimeout盡管它推遲時間為0,但是js不會立即執行,而是把它加入任務隊列,當執行完執行棧的同步任務也就是打印1后,再執行setTimeout的回調函數,打印0。
總之,setTimeout(fn,0)的含義是,指定某個任務在主線程最早可得的空閑時間執行,也就是說,盡可能早得執行。它在"任務隊列"的尾部添加一個事件,因此要等到同步任務和"任務隊列"現有的事件都處理完,才會得到執行。
所以注意的是,setTimeout()只是將事件插入了任務隊列,必須等到當前代碼(執行棧)執行完,主線程才會去執行它指定的回調函數。但如果當前任務十分耗時,需要等很久,所以并沒有辦法保證,回調函數一定會在setTimeout()指定的時間執行,比如說你指定10ms后執行,但是當前的任務執行了20ms,所以setTimeout的回調函數并不能在10ms后立即執行,可能要20ms后,如果setTimeout在任務隊列中不是排第一位,可能還不止20ms。
js異步編程的方法這個我還不是很懂~大家可以參考阮一峰老師的Javascript異步編程的4種方法
希望一包的文章可以幫到你們~
參考文章:
http://blog.csdn.net/qq_22855...(贊~)
https://www.cnblogs.com/woody...)
http://blog.csdn.net/kfanning...(贊~)
http://www.ruanyifeng.com/blo...(阮一峰老師嘛~)
http://www.cnblogs.com/smght/...(贊~)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107773.html
摘要:嚴格來說,并不是單線程的。其他異步和事件驅動相關的線程通過來實現內部的線程池和線程調度。線程是最小的進程,因此也是單進程的。子進程中執行的是非程序,提供一組參數后,執行的結果以回調的形式返回。在子進程中通過和的機制來接收和發送消息。 ??node遵循的是單線程單進程的模式,node的單線程是指js的引擎只有一個實例,且在nodejs的主線程中執行,同時node以事件驅動的方式處理IO...
摘要:主線程從任務隊列中讀取事件,這個過程是循環不斷的,所以整個的這種運行機制又稱為事件循環。上面也提到,在到達指定時間時,定時器就會將相應回調函數插入任務隊列尾部。這就是定時器功能。關于定時器的重要補充定時器包括與兩個方法。 一、引子 本文介紹JavaScript運行機制,這一部分比較抽象,我們先從一道面試題入手: console.log(1); setTimeout(function()...
摘要:主線程從任務隊列中讀取事件,這個過程是循環不斷的,所以整個的這種運行機制又稱為事件循環。上面也提到,在到達指定時間時,定時器就會將相應回調函數插入任務隊列尾部。這就是定時器功能。關于定時器的重要補充定時器包括與兩個方法。 一、引子 本文介紹JavaScript運行機制,這一部分比較抽象,我們先從一道面試題入手: console.log(1); setTimeout(function()...
摘要:主線程從任務隊列中讀取事件,這個過程是循環不斷的,所以整個的這種運行機制又稱為事件循環。上面也提到,在到達指定時間時,定時器就會將相應回調函數插入任務隊列尾部。這就是定時器功能。關于定時器的重要補充定時器包括與兩個方法。 一、引子 本文介紹JavaScript運行機制,這一部分比較抽象,我們先從一道面試題入手: console.log(1); setTimeout(function()...
閱讀 1754·2021-11-25 09:43
閱讀 1789·2021-11-24 10:41
閱讀 3108·2021-09-27 13:36
閱讀 815·2019-08-30 15:53
閱讀 3573·2019-08-30 15:44
閱讀 869·2019-08-30 14:03
閱讀 2578·2019-08-29 16:38
閱讀 1003·2019-08-29 13:23