JS筆試題(7)同步與異步

題目:

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

1.控制檯會輸出什麼?前端

2.若是咱們約定,用箭頭表示其先後的兩次輸出之間有 1 秒的時間間隔,而逗號表示其先後的兩次輸出之間的時間間隔能夠忽略,代碼實際運行的結果該如何描述?面試

答案:

  1. 555555。
  2. 5 -> 5,5,5,5,5,即直接輸出1個5,1 秒以後,輸出 5 個 5。

解析:

代碼執行過程以下:bash

(1)先用循環幾乎同時設置了5個定時器;而且i的值由0變成了5;微信

(2)循環體外console.log(i),打印1個5;閉包

(3)大約1秒以後,5個定時器都觸發,打印5個5。異步

setTimeout是Js最基本的異步函數,本題主要是對Js同步和異步知識點的考察,那麼這裏說的同步和異步究竟是什麼呢?函數

"同步",一下就讓人想到"一塊兒"這個詞;"異步"呢,從字面來說,像是"一邊...一邊...",好比"小明一邊吃雪糕一邊寫做業",雪糕吃完了,做業也寫完了,看起來徹底沒毛病,可是這樣理解Js的同步和異步就錯了!Javascript語言是一門單線程的語言,全部任務能夠分紅兩種,一種是同步任務,另外一種是異步任務。同步任務指的是,在"主線程"上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"的任務,只有等主線程任務執行完畢,"任務隊列"開始通知主線程,請求執行任務,該任務纔會進入主線程執行。ui

具體來講,異步執行的運行機制以下。(同步執行也是如此,由於它能夠被視爲沒有異步任務的異步執行。)spa

(1)全部同步任務都在主線程上執行,造成一個"執行棧"。線程

(2)主線程以外,還存在一個"任務隊列"。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。

(3)一旦"執行棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。那些對應的異步任務,結束等待狀態,進入執行棧,開始執行。

(4)主線程不斷重複上面的第三步。

題外話

若是指望代碼的輸出變成:5 -> 0,1,2,3,4,該怎麼改造代碼? 熟悉閉包的小夥伴很快能給出下面的解決辦法:

for (var i = 0; i < 5; i++) {
    (function(j) {  // j = i
        setTimeout(function() {
            console.log(j);
        }, 1000);
    })(i);
}
console.log(i);
複製代碼

巧妙的利用 IIFE(Immediately Invoked Function Expression:聲明即執行的函數表達式)來解決閉包形成的問題,確實是不錯的思路,可是初學者可能並不以爲這樣的代碼很好懂。有沒有更符合直覺的作法?咱們只須要對循環體稍作手腳,讓負責輸出的那段代碼能拿到每次循環的i值便可。

var output = function (i) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
};
 
for (var i = 0; i < 5; i++) {
    output(i);  // 這裏傳過去的 i 值被複制了
}
console.log(i);
複製代碼

感謝您花時間讀到這裏~

按照慣例,推廣一下微信公衆號「前端麻辣燙」,主要是分享前端知識,着重前端面試知識。歡迎關注~歡迎投稿~

微信搜索微信號:WebSnacks, 或者微信掃碼關注哦!

相關文章
相關標籤/搜索