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

資訊專欄INFORMATION COLUMN

js的單線程,異步及回調(diào)函數(shù)

Songlcy / 1223人閱讀

摘要:當主線程開始執(zhí)行異步任務,實際就是執(zhí)行對應的回調(diào)函數(shù)。異步任務必須指定回調(diào)函數(shù)。所以注意的是,只是將事件插入了任務隊列,必須等到當前代碼執(zhí)行棧執(zhí)行完,主線程才會去執(zhí)行它指定的回調(diào)函數(shù)。

最近本人對于js的運行機制,特別是異步,還有回調(diào)函數(shù)感覺很亂,于是參考了很多有用的博客(博客原文地址會在文末給出),整理如下:

js單線程

我們都知道,Javascript語言的執(zhí)行環(huán)境是"單線程"(single thread)。也就是說,瀏覽器只分配給js一個主線程用來執(zhí)行任務即函數(shù),但是每次只能執(zhí)行一個任務,只有等到當前任務執(zhí)行完成后,才執(zhí)行后面的任務,這些任務形成一個任務隊列排隊等候執(zhí)行,這一點和我們?nèi)粘5呐抨牶芟?,譬如排隊買奶茶,只有等到前面一個人買完奶茶付完錢,排在他后面的人才可以買奶茶。但是,當前面一個任務很耗時時,后面的任務就不得不等著,這時候整個程序的執(zhí)行效率就會下降,就像我們平時遇到的瀏覽器無響應即頁面假死往往是因為某段js代碼長時間運行如死循環(huán),導致頁面卡死,后面的任務無法執(zhí)行。

講到js的單線程,就不得不來了解一下瀏覽器

瀏覽器多線程


如圖,瀏覽器是一個多線程的執(zhí)行環(huán)境,在瀏覽器的內(nèi)核中分配了多個線程,其中瀏覽器常駐三大線程: js引擎線程,GUI渲染線程,瀏覽器事件觸發(fā)線程。最主要的線程之一即是js引擎的線程。由于這三個線程同時要訪問DOM樹,所以為了線程安全,瀏覽器內(nèi)部需要做互斥即當JS引擎在執(zhí)行代碼的時候,界面渲染和事件響應兩個線程是被暫停的。而所以當JS出現(xiàn)死循環(huán),瀏覽器無法響應點擊,也無法更新界面。

前面說到,前端會有一些任務十分耗時,而由于js是單線程使用會降低執(zhí)行效率,這些耗時的任務如網(wǎng)絡請求,定時器和事件監(jiān)聽。所以,瀏覽器為這些耗時任務開辟了另外的線程,主要包括http請求線程,瀏覽器定時觸發(fā)器,瀏覽器事件觸發(fā)線程,這些任務是異步的(見圖)。(詳細過程見此博文,博主講得很好~ 個人建議必須看一看哦~)

任務隊列

說回剛剛的js單線程,為了不讓前面的耗時任務導致的問題出現(xiàn),js的設計者把js的任務分為同步任務和異步任務。同步任務指的是,在主線程上排隊執(zhí)行的任務,只有前一個任務執(zhí)行完畢,才能執(zhí)行后一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執(zhí)行了,該任務才會進入主線程執(zhí)行。如我們剛剛所講到的瀏覽器為網(wǎng)絡請求開辟的http請求線程就是異步任務。

具體來說,異步執(zhí)行的運行機制如下。(同步執(zhí)行也是如此,因為它可以被視為沒有異步任務的異步執(zhí)行。)

(1)所有同步任務都在主線程上執(zhí)行,形成一個[執(zhí)行棧]。
(2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。
(3)一旦"執(zhí)行棧"中的所有同步任務執(zhí)行完畢,系統(tǒng)就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態(tài),進入執(zhí)行棧,開始執(zhí)行。
(4)主線程不斷重復上面的第三步。

(參考與阮一峰老師的博文JavaScript 運行機制詳解:再談Event Loop)

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

有了以上了解我們可以知道,主線程內(nèi)的同步任務執(zhí)行完畢后,就會執(zhí)行排在任務隊列第一位的異步任務,這個過程不斷重復。

當主線程開始執(zhí)行異步任務,實際就是執(zhí)行對應的回調(diào)函數(shù)。

我們來看一下例子:

setTimeout(function(){
    console.log("Hello");
},10);

執(zhí)行這段代碼,瀏覽器異步執(zhí)行計時操作(注意這里的瀏覽器模型定時計數(shù)器并不是由JavaScript引擎計數(shù)的),當10ms到了之后,就會觸發(fā)定時事件,這時就會把其中的回調(diào)函數(shù)放到任務隊列中,所以當主線程空閑時在任務隊列中“讀取”并且執(zhí)行的就是回調(diào)函數(shù)。

異步任務必須指定回調(diào)函數(shù)。

Event Loop

主線程從"任務隊列"中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為Event Loop(事件循環(huán))。

如圖,WebAPIs就是js線程外部的api如我們剛剛所說瀏覽器為異步任務所開辟的線程。而任務隊列就是callbackqueue,我們知道任務隊列中其實就是各種異步任務的回調(diào)函數(shù),從callbackqueue的直譯“回調(diào)隊列”也可看出。而heap堆和stack棧組成了js的主線程,當stack中的函數(shù)執(zhí)行完成后,就會在callbackqueue中尋找下一個任務并把它推入棧,這個尋找的過程就叫event loop(事件循環(huán))。

看了上面你是不是對js的運行機制有了了解呢~
我們把學會的知識來用一用:

js中的異步之定時器

說起js的異步,很多人第一反應是Ajax,但其實js中最基礎的異步就是setTimeout/setInterval。(小伙伴可不要把定時器忘了哦:))

我們以setTimeout為例,setTimeout接受兩個參數(shù),第一個是回調(diào)函數(shù),第二個是推遲執(zhí)行的毫秒數(shù)。

我們看看例子:

setTimeout(function(){
  console.log(0);
},0)
 
console.log(1);
 
// 1
 
// 0

是不是以為打印的順序是0,1?但大家注意哦,這時候瀏覽器打印的順序是1,0。大家可能疑問了,setTimeout中設置的推遲執(zhí)行的毫秒數(shù)是0呀,不就是立即執(zhí)行的意思嗎。大家還記得剛剛我們說了當有耗時任務時,會把它放在任務隊列中等待主線程空閑然后再執(zhí)行,實際在執(zhí)行程序的時候,瀏覽器會默認setTimeout以及ajax請求這一類的方法都是耗時程序(盡管可能不耗時),也就是上面說過的瀏覽器會為其異步開辟線程。所以此時的setTimeout盡管它推遲時間為0,但是js不會立即執(zhí)行,而是把它加入任務隊列,當執(zhí)行完執(zhí)行棧的同步任務也就是打印1后,再執(zhí)行setTimeout的回調(diào)函數(shù),打印0。

總之,setTimeout(fn,0)的含義是,指定某個任務在主線程最早可得的空閑時間執(zhí)行,也就是說,盡可能早得執(zhí)行。它在"任務隊列"的尾部添加一個事件,因此要等到同步任務和"任務隊列"現(xiàn)有的事件都處理完,才會得到執(zhí)行。

所以注意的是,setTimeout()只是將事件插入了任務隊列,必須等到當前代碼(執(zhí)行棧)執(zhí)行完,主線程才會去執(zhí)行它指定的回調(diào)函數(shù)。但如果當前任務十分耗時,需要等很久,所以并沒有辦法保證,回調(diào)函數(shù)一定會在setTimeout()指定的時間執(zhí)行,比如說你指定10ms后執(zhí)行,但是當前的任務執(zhí)行了20ms,所以setTimeout的回調(diào)函數(shù)并不能在10ms后立即執(zhí)行,可能要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/...(贊~)

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

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

相關文章

  • nodejs中的子進程,深入解析child_process模塊和cluster模塊

    摘要:嚴格來說,并不是單線程的。其他異步和事件驅(qū)動相關的線程通過來實現(xiàn)內(nèi)部的線程池和線程調(diào)度。線程是最小的進程,因此也是單進程的。子進程中執(zhí)行的是非程序,提供一組參數(shù)后,執(zhí)行的結果以回調(diào)的形式返回。在子進程中通過和的機制來接收和發(fā)送消息。 ??node遵循的是單線程單進程的模式,node的單線程是指js的引擎只有一個實例,且在nodejs的主線程中執(zhí)行,同時node以事件驅(qū)動的方式處理IO...

    JinB 評論0 收藏0
  • 深入淺出JavaScript運行機制

    摘要:主線程從任務隊列中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為事件循環(huán)。上面也提到,在到達指定時間時,定時器就會將相應回調(diào)函數(shù)插入任務隊列尾部。這就是定時器功能。關于定時器的重要補充定時器包括與兩個方法。 一、引子 本文介紹JavaScript運行機制,這一部分比較抽象,我們先從一道面試題入手: console.log(1); setTimeout(function()...

    mochixuan 評論0 收藏0
  • 深入淺出JavaScript運行機制

    摘要:主線程從任務隊列中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為事件循環(huán)。上面也提到,在到達指定時間時,定時器就會將相應回調(diào)函數(shù)插入任務隊列尾部。這就是定時器功能。關于定時器的重要補充定時器包括與兩個方法。 一、引子 本文介紹JavaScript運行機制,這一部分比較抽象,我們先從一道面試題入手: console.log(1); setTimeout(function()...

    魏明 評論0 收藏0
  • 深入淺出JavaScript運行機制

    摘要:主線程從任務隊列中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為事件循環(huán)。上面也提到,在到達指定時間時,定時器就會將相應回調(diào)函數(shù)插入任務隊列尾部。這就是定時器功能。關于定時器的重要補充定時器包括與兩個方法。 一、引子 本文介紹JavaScript運行機制,這一部分比較抽象,我們先從一道面試題入手: console.log(1); setTimeout(function()...

    chaosx110 評論0 收藏0

發(fā)表評論

0條評論

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