亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

如何通過setTimeout理解JS運行機制詳解

 更新時間:2019年03月23日 11:15:36   作者:番茄沙司  
這篇文章主要給大家介紹了關于如何通過setTimeout理解JS運行機制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用js具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧


setTimeout()函數(shù):用來指定某個函數(shù)或某段代碼在多少毫秒之后執(zhí)行。它返回一個整數(shù),表示定時器timer的編號,可以用來取消該定時器。

例子

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

問:最后的打印順序是什么?(如果不了解js的運行機制就會答錯)

正確答案:1 3 2

解析:無論setTimeout的執(zhí)行時間是0還是1000,結果都是先輸出3后輸出2,這就是面試官常??疾榈膉s運行機制的問題,接下來我們要引入一個概念,JavaScript 是單線程的。

二、 JavaScript 單線程

JavasScript引擎是基于事件驅動和單線程執(zhí)行的,JS引擎一直等待著任務隊列中任務的到來,然后加以處理,瀏覽器無論什么時候都只有一個JS線程在運行程序,即主線程。

通俗的說:JS在同一時間內只能做一件事,這也常被稱為 “阻塞式執(zhí)行”。

任務隊列

那么單線程的JavasScript是怎么實現(xiàn)“非阻塞執(zhí)行”呢?

答:異步容易實現(xiàn)非阻塞,所以在JavaScript中對于耗時的操作或者時間不確定的操作,使用異步就成了必然的選擇。
諸如事件點擊觸發(fā)回調函數(shù)、ajax通信、計時器這種異步處理是如何實現(xiàn)的呢?

答:任務隊列

所有任務可以分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous)。

任務隊列:一個先進先出的隊列,它里面存放著各種事件和任務。

同步任務

同步任務:在主線程上排隊執(zhí)行的任務,只有前一個任務執(zhí)行完畢,才能執(zhí)行后一個任務。

  • 輸出
  • 如:console.log()
  • 變量的聲明
  • 同步函數(shù):如果在函數(shù)返回的時候,調用者就能夠拿到預期的返回值或者看到預期的效果,那么這個函數(shù)就是同步的。

異步任務

  • setTimeout和setInterval
  • DOM事件
  • Promise
  • process.nextTick
  • fs.readFile
  • http.get
  • 異步函數(shù):如果在函數(shù)返回的時候,調用者還不能夠得到預期結果,而是需要在將來通過一定的手段得到,那么這個函數(shù)就是異步的。

除此之外,任務隊列又分為macro-task(宏任務)與micro-task(微任務),在ES5標準中,它們被分別稱為task與job。

宏任務

  1. I/O
  2. setTimeout
  3. setInterval
  4. setImmdiate
  5. requestAnimationFrame

微任務

  1. process.nextTick
  2. Promise
  3. Promise.then
  4. MutationObserver

宏任務和微任務的執(zhí)行順序

一次事件循環(huán)中,先執(zhí)行宏任務隊列里的一個任務,再把微任務隊列里的所有任務執(zhí)行完畢,再去宏任務隊列取下一個宏任務執(zhí)行。

注:在當前的微任務沒有執(zhí)行完成時,是不會執(zhí)行下一個宏任務的。

三、setTimeout運行機制

setTimeout 和 setInterval的運行機制是將指定的代碼移出本次執(zhí)行,等到下一輪 Event Loop 時,再檢查是否到了指定時間。如果到了,就執(zhí)行對應的代碼;如果不到,就等到再下一輪 Event Loop 時重新判斷。

這意味著,setTimeout指定的代碼,必須等到本次執(zhí)行的所有同步代碼都執(zhí)行完,才會執(zhí)行。

優(yōu)先關系:異步任務要掛起,先執(zhí)行同步任務,同步任務執(zhí)行完畢才會響應異步任務。

四、進階

console.log('A');
setTimeout(function () {
 console.log('B');
}, 0);
while (1) {}

大家再猜一下這段程序輸出的結果會是什么?

答:A

注:建議先注釋掉while循環(huán)代碼塊的代碼,執(zhí)行后強制刪除進程,不然會造成“假死”。

同步隊列輸出A之后,陷入while(true){}的死循環(huán)中,異步任務不會被執(zhí)行。

類似的,有時addEventListener()方法監(jiān)聽點擊事件click,用戶點了某個按鈕會卡死,就是因為當前JS正在處理同步隊列,無法將click觸發(fā)事件放入執(zhí)行棧,不會執(zhí)行,出現(xiàn)“假死”。

五、定時獲取接口更新數(shù)據

for (var i = 0; i < 4; i++) {
 setTimeout(function () {
 console.log(i);
 }, 1000);
}

輸出結果為,隔1s后一起輸出:4 4 4 4

for循環(huán)是一個同步任務,為什么連續(xù)輸出四個4?

答:因為有隊列插入的時間,即使執(zhí)行時間從1000改成0,還是輸出四個4。

那么這個問題是如何產生和解決的呢?請接著閱讀

異步隊列執(zhí)行的時間

執(zhí)行到異步任務的時候,會直接放到異步隊列中嗎?

答案是不一定的。

因為瀏覽器有個定時器(timer)模塊,定時器到了執(zhí)行時間才會把異步任務放到異步隊列。
for循環(huán)體執(zhí)行的過程中并沒有把setTimeout放到異步隊列中,只是交給定時器模塊了。4個循環(huán)體執(zhí)行速度非??欤ú坏?毫秒)。定時器到了設置的時間才會把setTimeout語句放到異步隊列中。

即使setTimeout設置的執(zhí)行時間為0毫秒,也按4毫秒算。

這就解釋了上題為什么會連續(xù)輸出四個4的原因。

HTML5 標準規(guī)定了setTimeout()的第二個參數(shù)的最小值,即最短間隔,不得低于4毫秒。如果低于這個值,就會自動增加。在此之前,老版本的瀏覽器都將最短間隔設為10毫秒。

利用閉包實現(xiàn) setTimeout 間歇調用

for (let i = 0; i < 4; i++) {
 (function (j) {
 setTimeout(function () {
  console.log(j);
 }, 1000 * i)
 })(i);
}

執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3

  • 此方法巧妙利用IIFE聲明即執(zhí)行的函數(shù)表達式來解決閉包造成的問題。
  • 將var改為let,使用了ES6語法。

這里也可以用setInterval()方法來實現(xiàn)間歇調用。

詳見:setTimeout和setInterval的區(qū)別

利用JS中基本類型的參數(shù)傳遞是按值傳遞的特征實現(xiàn)

var output = function (i) {
 setTimeout(function () {
 console.log(i);

 }, 1000 * i)
}
for (let i = 0; i < 4; i++) {
 output(i);
}

執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3

實現(xiàn)原理:傳過去的i值被復制了。

基于Promise的解決方案

const tasks = [];

const output = (i) => new Promise((resolve) => {
 setTimeout(() => {
 console.log(i);
 resolve();
 }, 1000 * i);

});

//生成全部的異步操作
for (var i = 0; i < 5; i++) {
 tasks.push(output(i));
}
//同步操作完成后,輸出最后的i
Promise.all(tasks).then(() => {
 setTimeout(() => {
 console.log(i);
 }, 1000)
})

執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3 4 5

優(yōu)點:提高了代碼的可讀性。

注意:如果沒有處理Promise的reject,會導致錯誤被丟進黑洞。

使用ES7中的async await特性的解決方案(推薦)

const sleep = (timeountMS) => new Promise((resolve) => {
 setTimeout(resolve, timeountMS);
});

(async () => { //聲明即執(zhí)行的async
 for (var i = 0; i < 5; i++) {
 await sleep(1000);
 console.log(i);
 }

 await sleep(1000);
 console.log(i);

})();

執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3 4 5

六、事件循環(huán) Event Loop


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

有時候 setTimeout明明寫的延時3秒,實際卻5,6秒才執(zhí)行函數(shù),這又是因為什么?

答:setTimeout 并不能保證執(zhí)行的時間,是否及時執(zhí)行取決于 JavaScript 線程是擁擠還是空閑。

瀏覽器的JS引擎遇到setTimeout,拿走之后不會立即放入異步隊列,同步任務執(zhí)行之后,timer模塊會到設置時間之后放到異步隊列中。js引擎發(fā)現(xiàn)同步隊列中沒有要執(zhí)行的東西了,即運行??樟司蛷漠惒疥犃兄凶x取,然后放到運行棧中執(zhí)行。所以setTimeout可能會多了等待線程的時間。

這時setTimeout函數(shù)體就變成了運行棧中的執(zhí)行任務,運行??樟?,再監(jiān)聽異步隊列中有沒有要執(zhí)行的任務,如果有就繼續(xù)執(zhí)行,如此循環(huán),就叫Event Loop。

七、總結

JavaScript通過事件循環(huán)和瀏覽器各線程協(xié)調共同實現(xiàn)異步。同步可以保證順序一致,但是容易導致阻塞;異步可以解決阻塞問題,但是會改變順序性。

知識點梳理:

  • 理解JS的單線程的概念:一段時間內做一件事
  • 理解任務隊列:同步任務、異步任務
  • 理解 Event Loop
  • 理解哪些語句會放入異步任務隊列
  • 理解語句放入異步任務隊列的時機

最后,希望大家閱后有所收獲。🤠

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

相關文章

  • Bootstrap?按鈕下拉菜單的實現(xiàn)示例

    Bootstrap?按鈕下拉菜單的實現(xiàn)示例

    本文主要介紹了Bootstrap?按鈕下拉菜單的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • JS面試必備之如何實現(xiàn)一個精確的倒計時

    JS面試必備之如何實現(xiàn)一個精確的倒計時

    又到了金三銀四的季節(jié)了,面試的各位同學要開始準備起來了,今天主要分享一個在面試中經常被提到的一個面試題:倒計時,希望對大家有所幫助
    2024-03-03
  • Bootstrap每天必學之導航條(二)

    Bootstrap每天必學之導航條(二)

    Bootstrap每天必學之導航條,進一步向大家講解了導航條養(yǎng)殖,以及導航條中元素的使用方法,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 梳理總結JavaScript的23個String方法

    梳理總結JavaScript的23個String方法

    文章主要介紹了梳理總結JavaScript的23個String方法,JavaScript?中的String類型用于表示文本型的數(shù)據。它是由無符號整數(shù)值作為元素而組成的集合,更多詳細內容需要的朋友可以參考一下
    2022-07-07
  • 利用Javascript開發(fā)一個二維周視圖日歷

    利用Javascript開發(fā)一個二維周視圖日歷

    這篇文章主要給大家介紹了關于利用Javascript如何開發(fā)一個二維周視圖日歷的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-12-12
  • 使用JavaScript實現(xiàn)文本收起展開(省略)功能

    使用JavaScript實現(xiàn)文本收起展開(省略)功能

    省略號,作為一種常見的文本處理方式,在很多情況下都十分常見,特別是當我們需要在省略號后面添加額外文字時,本文為大家介紹了使用JavaScript實現(xiàn)文本收起展開功能的相關方法,希望對大家有所幫助
    2024-04-04
  • js sort 二維數(shù)組排序的用法小結

    js sort 二維數(shù)組排序的用法小結

    我們知道在js中默認提供了sort函數(shù),但是這個函數(shù)默認是按照數(shù)組內容的ascii碼升序進行排列的,如果我們要對二維數(shù)組排序要如何做呢
    2014-01-01
  • 原生JS實現(xiàn)音樂播放器

    原生JS實現(xiàn)音樂播放器

    這篇文章主要為大家詳細介紹了原生JS音樂播放器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • JS實現(xiàn)的論壇Ajax打分效果完整實例

    JS實現(xiàn)的論壇Ajax打分效果完整實例

    這篇文章主要介紹了JS實現(xiàn)的論壇Ajax打分效果,以完整實例形式分析了JavaScript響應鼠標事件動態(tài)操作頁面元素樣式的相關技巧,需要的朋友可以參考下
    2015-10-10
  • JavaScript常見的五種數(shù)組去重的方式

    JavaScript常見的五種數(shù)組去重的方式

    本文主要JavaScript常見的五種數(shù)組去重的方式進行一一思路分析實例介紹,易于理解與學習,具有很好的參考價值,需要的朋友一起來看下吧
    2016-12-12

最新評論