成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

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

Songlcy / 1253人閱讀

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

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

js單線程

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

講到j(luò)s的單線程,就不得不來了解一下瀏覽器

瀏覽器多線程


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

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

任務(wù)隊(duì)列

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

具體來說,異步執(zhí)行的運(yùn)行機(jī)制如下。(同步執(zhí)行也是如此,因?yàn)樗梢员灰暈闆]有異步任務(wù)的異步執(zhí)行。)

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

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

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

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

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

我們來看一下例子:

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

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

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

Event Loop

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

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

看了上面你是不是對(duì)js的運(yùn)行機(jī)制有了了解呢~
我們把學(xué)會(huì)的知識(shí)來用一用:

js中的異步之定時(shí)器

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

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

我們看看例子:

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

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

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

所以注意的是,setTimeout()只是將事件插入了任務(wù)隊(duì)列,必須等到當(dāng)前代碼(執(zhí)行棧)執(zhí)行完,主線程才會(huì)去執(zhí)行它指定的回調(diào)函數(shù)。但如果當(dāng)前任務(wù)十分耗時(shí),需要等很久,所以并沒有辦法保證,回調(diào)函數(shù)一定會(huì)在setTimeout()指定的時(shí)間執(zhí)行,比如說你指定10ms后執(zhí)行,但是當(dāng)前的任務(wù)執(zhí)行了20ms,所以setTimeout的回調(diào)函數(shù)并不能在10ms后立即執(zhí)行,可能要20ms后,如果setTimeout在任務(wù)隊(duì)列中不是排第一位,可能還不止20ms。

js異步編程的方法

這個(gè)我還不是很懂~大家可以參考阮一峰老師的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/...(贊~)

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/107773.html

相關(guān)文章

  • nodejs中的子進(jìn)程,深入解析child_process模塊和cluster模塊

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

    JinB 評(píng)論0 收藏0
  • 深入淺出JavaScript運(yùn)行機(jī)制

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

    mochixuan 評(píng)論0 收藏0
  • 深入淺出JavaScript運(yùn)行機(jī)制

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

    魏明 評(píng)論0 收藏0
  • 深入淺出JavaScript運(yùn)行機(jī)制

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

    chaosx110 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<