javascript
javascript真的是异步的吗?且看setTimeout的实现原理以及setTimeout(0)的使用场景
在今天之前我一直以為setTimeout這個函數是異步的,無意中看到了一篇關于setTimeout的文章。發現自己曾經的認識全是錯誤的,趕緊總結下。
先看一段代碼:
var start = new Date(); setTimeout(function(){var end = new Date();console.log("Time elapsed: ", end - start, "ms"); }, 500);while (new Date - start <= 1000) {}
運行這段腳本能夠看到:Time elapsed的值大概在1001ms左右,肯定會超過1000ms。也就是說:setTimeout失效了,指定的函數并沒有在500ms后運行。而是延遲到1000ms后才運行。
再看一段代碼:
function a() {setTimeout(function(){console.log(1);},0);console.log(2); } a();
執行這段腳本能夠看到:先打印2后打印1,我們在setTimeout里面指定了0ms,希望能馬上執行,可是實際上沒有效果。
想要理解上面的2段代碼,我們得了解一下javascript中setTimeout的實現原理。首先牢記一點:JavaScript 是單線程運行的,也就是無法同一時候運行多段代碼。
以下這段解釋來自這篇博客:
? ? ? ? JavaScript是單線程運行的,無法同一時候運行多段代碼。當某一段代碼正在運行的時候,全部興許的任務都必須等待,形成一個隊列。
一旦當前任務運行完畢,再從隊列中取出下一個任務,這也常被稱為 “堵塞式運行”。所以一次鼠標點擊,或是計時器到達時間點,或是Ajax請求完畢觸發了回調函數。這些事件處理程序或回調函數都不會馬上運行,而是馬上排隊。一旦線程有空暇就運行。假如當前 JavaScript線程正在運行一段非常耗時的代碼,此時發生了一次鼠標點擊。那么事件處理程序就被堵塞。用戶也無法馬上看到反饋。事件處理程序會被放入任務隊列。直到前面的代碼結束以后才會開始運行。假設代碼中設定了一個 setTimeout,那么瀏覽器便會在合適的時間。將代碼插入任務隊列。假設這個時間設為 0,就代表馬上插入隊列,但不是馬上運行。仍然要等待前面代碼運行完成。
所以 setTimeout 并不能保證運行的時間。是否及時運行取決于 JavaScript 線程是擁擠還是空暇。
也就是說setTimeout僅僅能保證在指定的時間過后將任務(須要運行的函數)插入隊列等候,并不保證這個任務在什么時候運行。運行javascript的線程會在空暇的時候,自行從隊列中取出任務然后運行它。javascript通過這樣的隊列機制。給我們制造一個異步運行的假象。
var start = new Date(); setTimeout(function(){var end = new Date();console.log("Time elapsed: ", end - start, "ms"); }, 500);console.log("task finished.");我們之所以會感覺到這段代碼是在異步運行,這是由于javascript線程并沒有由于什么耗時操作而堵塞,所以能夠非常快地取出排隊隊列中的任務然后運行它。
如今我們知道了setTimeout的原理了,如今看下setTimeout(0)的使用場景。以下這個樣例來自這篇文章。
<input type="text" οnkeydοwn="show(this.value)"> <div></div> <script type="text/javascript">function show(val) {document.getElementsByTagName('div')[0].innerHTML = val;} </script>這里綁定了 keydown 事件,意圖是當用戶在文本框里輸入字符時。將輸入的內容實時地在 <div> 中顯示出來??墒菍嶋H效果并不是如此,能夠發現。每按下一個字符時,<div> 中僅僅能顯示出之前的內容,無法得到當前的字符。<input type="text" οnkeydοwn="var self=this; setTimeout(function() {show(self.value)}, 0)"> <div></div> <script type="text/javascript">function show(val) {document.getElementsByTagName('div')[0].innerHTML = val;} </script>
這段代碼使用了setTimeout(0)就能夠實現需要的效果了。
這里事實上涉及2個任務,1個是將鍵盤輸入的字符回寫到輸入框中。一個是獲取文本框的值將其寫入div中。第一個是瀏覽器自身的默認行為。一個是我們自己編寫的代碼。非常顯然。必需要先讓瀏覽器將字符回寫到文本框。然后我們才干獲取其內容寫到div中。改變順序,這這正是setTimeout(0)的作用。
參考文章:setTimeout(0) 的作用
總結
以上是生活随笔為你收集整理的javascript真的是异步的吗?且看setTimeout的实现原理以及setTimeout(0)的使用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux面试题,浅析常见Linux命令
- 下一篇: LinkedList专题1