console.log('111'); setTimeout(()=>{ console.log('222') },1000); console.log('333'); setTimeout(()=>{ console.log('444') },0); console.log(555);
就是執行這樣一段js代碼 , 打印出來的結果是 :
111 -> 333 -> 555 -> 444 -> 222
(結果就是我們理論起來 setTimeout 到底是同步還是異步的 ?為什么會這樣執行 ? JavaScript不是一門單線程的語言嗎?)
了解setTimeout 與 clearTimeout
setTimeout 接受兩個參數,第一個是包含js代碼的字符串和函數,第二個參數是等待多長時間的毫秒數,但經過該事件指定的代碼不一定執行(下面講解緣由)。clearTimeout 接受一個setTimeout 返回的id 值作為參數傳遞給它,取消代碼的執行。
//設置超時調用 var timeoutId = setTimeout(function (){ alert("hello World"); },1000); //取消掉用的代碼 clearTimeout(timeoutId);
JavaScript中沒有任何代碼是立即執行的,但是只用進程一旦空閑就會立即執行,所以題目中設置的事件不過是經過多少毫秒數被添加到了隊列中,而不是經過多少時間后就被執行。
在這里,我們需要有一點進程,線程的知識來支撐我們理解js中同步,異步的編程思想
眾所周知,javascript是一門單線程的語言,即在js引擎中負責解釋和執行js代碼的線程只能有一個,但是,我們知道瀏覽器是多線程的。html5中提出了新的web標准,允許javascript 腳本創建多個線程,但子線程完全受主線程控制,且不得進行Dom操作,因此也並沒有改變單線程的本質。
同步異步的理解
同步:假如一個函數返回時,調用者就能夠得到預期結果(拿到了預期的返回值或者看到了預期的效果),這就是同步函數。
alert("hello World"); console.log("hello World");
異步:調用一個函數,返回的值不是預期的結果,需要通過一定的手段才能得到預期的返回值,這就是異步函數
var timeoutId = setTimeout(function (){ alert("hello World"); },1000)
異步執行的過程:
主線程發起一個異步請求,相應的工作線程(比如瀏覽器的其他線程)接收請求並告知主線程已收到(異步函數返回);主線程可以繼續執行后面的代碼,同時工作線程執行異步任務;工作線程完成工作后,通知主線程;主線程收到通知后,執行一定的動作(調用回調函數)。(工作線程將消息放到消息隊列中,主線程通過時間循環去逐個取信息,)
發起函數 – 發起異步過程
回調函數 – 返回處理結果
事件循環的機制
主線程只會做一件事,就是從消息隊列里面取消息、執行消息。當消息隊列為空時,就會等待消息隊列變成非空。只有當前的消息執行結束,才會去取下一個消息。這種機制就叫做事件循環機制Event Loop,取一個消息並執行的過程叫做一次循環。
setTimeout 函數的解決
在了解了以上的知識點后,我們就能夠對setTimeout 函數有很好的理解,在執行我們本頁開始的代碼的時候,先在控制台輸出 one ,然后主線程發起異步請求,工作線程接受請求,將setTimeout 經過設置的時間數推入消息隊列,最終通過事件循環取出消息進行調用,這就是我們剛才開始看到結果的原因了。
setTimeout 到底是同步還是異步的 ?
除了放置異步任務的事件,"任務隊列"還可以放置定時事件。
setTimeout()接受兩個參數,第一個是回調函數,第二個是推遲執行的毫秒數。
需要注意的是,setTimeout()只是將事件插入了"任務隊列",必須等到當前代碼(執行棧)執行完,主線程才會去執行它指定的回調函數。要是當前代碼耗時很長,有可能要等很久,所以並沒有辦法保證,回調函數一定會在setTimeout()指定的時間執行。
綜上所屬
setTimeout是單線程,類似異步,但不是異步 。