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

資訊專(zhuān)欄INFORMATION COLUMN

你不知道的Javascript:有趣的setTimeout

whjin / 2198人閱讀

摘要:?jiǎn)尉€程就意味著,所有任務(wù)需要排隊(duì),前一個(gè)任務(wù)結(jié)束,才會(huì)執(zhí)行后一個(gè)任務(wù)。為了優(yōu)化單線程的性能,將任務(wù)分成兩種,一種是同步任務(wù),另一種是異步任務(wù)。每次循環(huán)的迭代,都將中的回調(diào)函數(shù)加入任務(wù)隊(duì)列等待執(zhí)行。

今天在回顧JavaScript進(jìn)階用法的時(shí)候,發(fā)現(xiàn)一個(gè)有趣的問(wèn)題,話不多說(shuō),先上代碼:

for(var j=0;j<10;j++){
  setTimeout(function(){console.log(j)},5000)
}

看到這三行代碼,也許你會(huì)不耐煩道:又要講閉包?要吐了好么?別急,讓我們先來(lái)思考一下,這段代碼在瀏覽器中的執(zhí)行結(jié)果是什么?

甲:順序打印0到9?

乙:這題我見(jiàn)過(guò),打印十個(gè)10!

哪個(gè)答案正確?我們繼續(xù)上圖:

執(zhí)行結(jié)果顯示,瀏覽器打印出了十個(gè)10(因?yàn)閳D片處理的原因,按下回車(chē)到打印之前其實(shí)間隔了5秒左右),貌似乙勝出了。但如果你足夠細(xì)心,你會(huì)發(fā)現(xiàn)幾個(gè)問(wèn)題:

為什么會(huì)循環(huán)打印十個(gè)10而不是0到9?

從結(jié)果來(lái)看,for循環(huán)執(zhí)行完跳出之后,才開(kāi)始執(zhí)行setTimeout(所以j才等于10),為什么不是每次迭代都執(zhí)行一次setTimeout呢?

如果上述三個(gè)問(wèn)題你都能回答上來(lái),恭喜你,你已經(jīng)開(kāi)始掌握了JavaScript深層次的知識(shí),如果不能,那就乖乖往下看吧!

為什么會(huì)循環(huán)打印十個(gè)10

許多人習(xí)慣用第二個(gè)問(wèn)題中的執(zhí)行結(jié)果來(lái)回答這個(gè)問(wèn)題:“for循環(huán)執(zhí)行完跳出之后,才開(kāi)始執(zhí)行setTimeout,所以才打印了十個(gè)10”。這樣的答案,只能說(shuō)是既應(yīng)付了自己,又應(yīng)付了別人。其實(shí),要解答第一個(gè)問(wèn)題,首先要解答的就是第二的問(wèn)題。

為什么不是每次迭代都執(zhí)行一次setTimeout

大家都知道,JavaScript在ES6出現(xiàn)以前,是沒(méi)有塊狀作用域的,這就意味著, 在for循環(huán)中用var定義的變量j,其實(shí)是屬于全局的,即在全局范圍內(nèi)都可以被訪問(wèn)到,既然如此,那其實(shí)整個(gè)全局作用域中就只有一個(gè)j,每次for循環(huán)都i是在更新這個(gè)j。

那么現(xiàn)在關(guān)鍵的問(wèn)題在于,為什么整個(gè)for循環(huán)會(huì)先于setTimeout執(zhí)行,而不是我們正常理解的,一次迭代執(zhí)行一次。

這就涉及到了JavaScript的核心特性:?jiǎn)尉€程。

JavaScript設(shè)計(jì)的初衷,是瀏覽器用來(lái)與用戶(hù)進(jìn)行交互和DOM操作的。這就決定了它必須是單線程的,設(shè)想JavaScript同事有兩個(gè)線程,一個(gè)線程在DOM節(jié)點(diǎn)添加內(nèi)容,一個(gè)線程刪除該節(jié)點(diǎn),瀏覽器就會(huì)出現(xiàn)混亂。所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成了這門(mén)語(yǔ)言的核心特征,將來(lái)也不會(huì)改變。

單線程就意味著,所有任務(wù)需要排隊(duì),前一個(gè)任務(wù)結(jié)束,才會(huì)執(zhí)行后一個(gè)任務(wù)。如果前一個(gè)任務(wù)耗時(shí)很長(zhǎng),后一個(gè)任務(wù)就不得不一直等著。

為了優(yōu)化單線程的性能,JavaScript將任務(wù)分成兩種,一種是同步任務(wù)(synchronous),另一種是異步任務(wù)(asynchronous)。同步任務(wù)指的是,在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù);異步任務(wù)指的是,不進(jìn)入主線程、而進(jìn)入"任務(wù)隊(duì)列"(task queue)的任務(wù),只有主線程中的同步任務(wù)執(zhí)行完畢,異步任務(wù)才會(huì)進(jìn)入執(zhí)行隊(duì)列執(zhí)行。只要主線程空了,就會(huì)去讀取"任務(wù)隊(duì)列",這就是JavaScript的運(yùn)行機(jī)制。這個(gè)過(guò)程會(huì)不斷重復(fù)。

而setTimeout,就被JavaScript定義為異步任務(wù)。每次for循環(huán)的迭代,都將setTimeout中的回調(diào)函數(shù)加入任務(wù)隊(duì)列等待執(zhí)行。也就是說(shuō),只有同步任務(wù)中的for循環(huán)完全結(jié)束,主線程中才會(huì)去任務(wù)隊(duì)列中找到尚未執(zhí)行的十個(gè)setTimeout(十次迭代)回調(diào)函數(shù)并順序執(zhí)行(先進(jìn)先出)。而此時(shí),i已經(jīng)經(jīng)過(guò)循環(huán)結(jié)束變成了10,所以,此時(shí)主線程執(zhí)行的,是十個(gè)一摸一樣的打印i的回調(diào)函數(shù),即打印十個(gè)10。至此就完美回答了第一和第二個(gè)問(wèn)題,文章開(kāi)頭的代碼與下面的代碼其實(shí)是等價(jià)的:

for(var i=0;i<10;i++){}
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)

小小的一個(gè)setTimeout,牽扯出了很多JavaScript的深層次問(wèn)題,雖然總結(jié)成一篇文章只有區(qū)區(qū)數(shù)百字,但是我在成文的過(guò)程中查閱了大量的資料,也做了許多實(shí)驗(yàn)。

最后,給出一個(gè)很小但是仍然在困擾我的一個(gè)問(wèn)題,希望有興趣的小伙伴可以跟我一起研究:

setTimeout(function(){while(true){}},6000);
setTimeout(function(){console.log(1)},10000);
setTimeout(function(){console.log(2)},5000);

上述代碼的執(zhí)行順序是怎樣的?setTimeout的定時(shí),是定時(shí)插入執(zhí)行棧之后立即執(zhí)行,還是立即插入執(zhí)行棧定時(shí)執(zhí)行?

期待大家的留言。

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

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

相關(guān)文章

  • 還擔(dān)心面試官問(wèn)閉包?

    摘要:一言以蔽之,閉包,你就得掌握。當(dāng)函數(shù)記住并訪問(wèn)所在的詞法作用域,閉包就產(chǎn)生了。所以閉包才會(huì)得以實(shí)現(xiàn)。從技術(shù)上講,這就是閉包。執(zhí)行后,他的內(nèi)部作用域并不會(huì)消失,函數(shù)依然保持有作用域的閉包。 網(wǎng)上總結(jié)閉包的文章已經(jīng)爛大街了,不敢說(shuō)筆者這篇文章多么多么xxx,只是個(gè)人理解總結(jié)。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結(jié)與《JavaScript忍者秘籍》 《你不知道的JavaScri...

    tinyq 評(píng)論0 收藏0
  • 你不知道javascript》筆記_this

    下一篇:《你不知道的javascript》筆記_對(duì)象&原型 寫(xiě)在前面 上一篇博客我們知道詞法作用域是由變量書(shū)寫(xiě)的位置決定的,那this又是在哪里確定的呢?如何能夠精準(zhǔn)的判斷this的指向?這篇博客會(huì)逐條闡述 書(shū)中有這樣幾句話: this是在運(yùn)行時(shí)進(jìn)行綁定的,并不是在編寫(xiě)時(shí)綁定,它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件this的綁定和函數(shù)聲明的位置沒(méi)有任何關(guān)系,只取決于函數(shù)的調(diào)用方式當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)...

    cpupro 評(píng)論0 收藏0
  • 【筆記】 你不知道JS讀書(shū)筆記——異步

    摘要:異步請(qǐng)求線程在在連接后是通過(guò)瀏覽器新開(kāi)一個(gè)線程請(qǐng)求將檢測(cè)到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件循環(huán)隊(duì)列中。 基礎(chǔ):瀏覽器 -- 多進(jìn)程,每個(gè)tab頁(yè)獨(dú)立一個(gè)瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核) 每個(gè)瀏覽器渲染進(jìn)程是多線程的,主要包括:GUI渲染線程 JS引擎線程 也稱(chēng)為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎) JS引擎線程負(fù)...

    junnplus 評(píng)論0 收藏0
  • JavaScript引擎是如何工作?從調(diào)用棧到Promise你需要知道一切

    摘要:最受歡迎的引擎是,在和中使用,用于,以及所使用的。怎么處理每個(gè)引擎都有一個(gè)基本組件,稱(chēng)為調(diào)用棧。也就是說(shuō),如果有其他函數(shù)等待執(zhí)行,函數(shù)是不能離開(kāi)調(diào)用棧的。每個(gè)異步函數(shù)在被送入調(diào)用棧之前必須通過(guò)回調(diào)隊(duì)列。例如方法是在中傳遞的回調(diào)函數(shù)。 ? 翻譯:瘋狂的技術(shù)宅 原文:www.valentinog.com/blog/engine… 從Call Stack,Global Me...

    zzbo 評(píng)論0 收藏0
  • 你不知道JavaScript :Promise 與 Async/Await

    摘要:前言對(duì)于這門(mén)語(yǔ)言,其實(shí)我更喜歡稱(chēng)它為,從一開(kāi)始我們就已經(jīng)涉及到異步編程,但是多數(shù)開(kāi)發(fā)者從來(lái)沒(méi)有認(rèn)真思考過(guò)自己程序中的異步,到底是怎么實(shí)現(xiàn)的,以及為什么會(huì)出現(xiàn)。 前言 對(duì)于JavaScript這門(mén)語(yǔ)言,其實(shí)我更喜歡稱(chēng)它為ECMAScript,從一開(kāi)始我們就已經(jīng)涉及到異步編程,但是多數(shù)JavaScript開(kāi)發(fā)者從來(lái)沒(méi)有認(rèn)真思考過(guò)自己程序中的異步,到底是怎么實(shí)現(xiàn)的,以及為什么會(huì)出現(xiàn)。但是由于...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<