對JavaScript呼叫堆疊和setTimeout用法的深入研究
Javascript中會經常用到setTimeout來推遲一個函式的執行,如:
setTimeout(function(){alert("Hello World");},1000)
會在執行到這句話後延遲1秒鐘來彈出alert視窗。那麼再看這一段:
function a() {
setTimeout(function() {alert(1)}, 0);
alert(2);
}
a();
注意這段程式碼中的setTimeout延遲設為了0,就是延遲0毫秒,貌似是不做任何延遲立刻執行,即1,2。但實際的執行結果確是2,1。為什麼?這得從Javascript呼叫堆疊(call stack)和setTimeout的功能說起。
首先,JavaScript是單執行緒的,即同一時間只執行一條程式碼,所以每一個JavaScript程式碼執行塊會“阻塞”其它非同步事件的執行。其次,和其他的程式語言一樣,Javascript中的函式呼叫也是通過堆疊實現的。在執行函式a的時候,a先入棧,如果不給alert(1)加setTimeout,那麼alert(1)第2個入棧,最後是alert(2)。但現在給alert(1)加上setTimeout後,alert(1)就被加入到了一個新的堆疊中等待,並“儘可能快”的執行。這個儘可能快就是指在a的堆疊完成後就立刻執行,因此實際的執行結果就是先alert(2),再alert(1)。在這裡setTimeout實際上是讓alert(1)脫離了當前函式呼叫堆疊。看下面一個例子:
<input name="input" onkeydown="alert(this.value)" type="text" value="a" />
這樣一段函式意圖是每輸入一個字元就把當前input裡的所有字元都alert出來,但實際效果確是alert出按鍵之前的內容。這裡,我們就可以利用setTimeout(0)來實現。
<input onkeydown="var me=this; setTimeout(function(){alert(me.value)}, 0)" name="input" type="text" value="a" />
這樣當onkeydown事件觸發的時候,alert就被放入了下一個呼叫堆疊,一旦onkeydown事件觸發的堆疊關閉後就開始執行。當然瀏覽器還有個onkeyup事件也可以實現我們的需求。
這樣的setTimeout用法在實際專案中還是會時常遇到。比如瀏覽器會聰明的等到一個函式堆疊結束後才改變DOM,如果再這個函式堆疊中把頁面背景先從白色設為紅色,再設回白色,那麼瀏覽器會認為DOM沒有發生任何改變而忽略這兩句話,因此我們可以通過setTimeout把“設回白色”函式加入下一個堆疊,那麼就可以確保背景顏色發生過改變了(雖然速度很快可能無法被察覺)。
總之,setTimeout增加了Javascript函式呼叫的靈活性,為函式執行順序的排程提供極大便利。
推薦閱讀jQuery作者John的一篇文章:How JavaScript Timers Work,你會對JavaScript單執行緒本質和setTimeout以及setInterval有更加深刻的理解。
相關文章
- JavaScript的工作原理:引擎,執行時和呼叫堆疊JavaScript
- [譯] JavaScript 如何工作:對引擎、執行時、呼叫堆疊的概述JavaScript
- 解讀 JavaScript 之引擎、執行時和堆疊呼叫JavaScript
- JavaScript是如何工作的:引擎,執行時和呼叫堆疊的概述!JavaScript
- 【譯】JavaScript的工作原理:引擎,執行時和呼叫堆疊的概述JavaScript
- [golang]如何看懂呼叫堆疊Golang
- JavaScript 工作原理之一-引擎,執行時,呼叫堆疊(譯)JavaScript
- 函式呼叫中堆疊的個人理解函式
- 利用Decorator和SourceMap優化JavaScript錯誤堆疊優化JavaScript
- 深入理解 JavaScript 錯誤和堆疊追蹤JavaScript
- C#中堆和堆疊的區別C#
- JavaScript 錯誤處理和堆疊追蹤淺析JavaScript
- JavaScript中的執行上下文和堆疊是什麼JavaScript
- 聊一聊JavaScript中的執行上下文和堆疊JavaScript
- JavaScript 值型別和引用型別在堆疊中的存放JavaScript型別
- javascript堆疊記憶體分配的區別JavaScript記憶體
- 圖的深度優先遍歷(堆疊實現和非堆疊實現)
- 瞭解Javascript中的執行上下文和執行堆疊JavaScript
- VC++ 崩潰處理以及列印呼叫堆疊C++
- JS 堆疊JS
- java堆疊Java
- 堆疊圖
- 平衡堆疊
- 堆疊的應用——用JavaScript描述資料結構JavaScript資料結構
- 堆疊的工作原理
- PHP列印呼叫函式入口地址(堆疊),方便調式PHP函式
- 圖的深度優先遍歷[非堆疊、堆疊實現]
- JS 資料型別和堆疊JS資料型別
- CSS之定位和堆疊屬性CSS
- JavaScript setTimeout()JavaScript
- 從彙編視角解析函式呼叫中的堆疊運作函式
- 與 AI 互動 - 學習如何看呼叫鏈堆疊資訊AI
- thinkphp console 命令列列印錯誤呼叫堆疊PHP命令列
- Thrift的網路堆疊
- JavaScript - 函式 setTimeout 和 setInterval 的比較JavaScript函式
- 堆疊和記憶體的關係 細說記憶體
- setTimeout()和setInterval() 何時被呼叫執行
- Javascript中遞迴造成的堆疊溢位及解決方案JavaScript遞迴