開發中經常使用setTimeout進行一些延遲操作。昨天突然想了解下setTimeout的handler到底在隊列中的什么位置特別好奇。今天特地來測試下。
定義和用法
setTimeout() 方法用於在指定的毫秒數后調用函數或計算表達式。
語法
setTimeout(code,millisec)
參數 | 描述 |
---|---|
code | 必需。要調用的函數后要執行的 JavaScript 代碼串。 |
millisec | 必需。在執行代碼前需等待的毫秒數。 |
提示和注釋
提示:setTimeout() 只執行 code 一次。如果要多次調用,請使用 setInterval() 或者讓 code 自身再次調用 setTimeout()。
以上定義來源於w3school.com
JavaScirpt線程
先了解下瀏覽器,瀏覽器是多線程的。
- JavaScript引擎線程
- 界面渲染線程
- 瀏覽器事件觸發線程
- Http請求線程
JS運行在瀏覽器中,是單線程的,每個window一個JS引擎線程。既然是單線程的,的在某個特定的時刻只有特定代碼能被執夠行,並阻塞其它的代碼。(至於ajax的實現這里就不說了。)
原理
來了解下setTimeout的簡單的原理:
setTimeout調用的時候,JavaScript引擎會啟動定時器timer,大約millisec(ms)以后執行code,當定時器時間到,就把該事件放到主事件隊列等待處理。
注意:
瀏覽器JavaScript線程空閑的時候才會真正執行
為什么呢?因為當JavaScript線程的正在出來其他JavaScript代碼時,其實以已經阻塞了其他的代碼,其中包括的setTimeout的定時器部分的實現。
代碼測試
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script type="text/javascript">
function testHandler() { console.log("調用了setTimeout的函數"); } window.onload = function () { console.log("開始"); console.log("設置setTimeout 100ms"); setTimeout(testHandler,100); console.log("休眠1000ms"); sleep(1000); testNext(); console.log("結束"); } function testNext() { console.log("后續執行的函數"); } function sleep(number) { var now = new Date(); var exitTime = now.getTime() + number; while (true) { now = new Date(); if (now.getTime() > exitTime) return; } } </script>
</head>
<body>
</body>
</html>
最終瀏覽器輸出的結果:
此處setTimeout其實只延遲了100ms。而進setTimeout到結束中先模擬休眠了2000ms,然后再執行了testNext函數。但是從測試結果來看實際上testHandler卻是在整個隊列的最后。這就解釋了上訴中說的,setTimeout將code加入到隊列的操作必須是在線程空閑的時候才會執行了。
millisec參數有什么用?
上訴測試發現,實際應用中。setTimeout的millisec參數不管你設置多少,實際執行都是在線程的最后,因為在執行一個操作的時候,JavaScript肯定是一直把代碼執行完后再走setTimeout綁定的code的。
那么問題來了。setTimeout(handler,0)和setTimeout(handler,100)在單獨使用時,好像並沒有區別。(中間執行的代碼處理時間超過100ms時)
<script type="text/javascript">
function testHandler() { console.log("調用了setTimeout的函數"); } window.onload = function () { console.log("開始"); console.log("設置setTimeout 100ms"); setTimeout(testHandler,100); setTimeout(function () { console.log("調用了setTimeout的函數2"); }, 50); console.log("休眠1000ms"); sleep(1000); testNext(); console.log("結束"); } function testNext() { console.log("后續執行的函數"); } function sleep(number) { var now = new Date(); var exitTime = now.getTime() + number; while (true) { now = new Date(); if (now.getTime() > exitTime) return; } } </script>
輸出結果:
個人認為millisec一般在多個setTimeout一起使用的時,需要區分哪個先加入到隊列的時候才有用,否則都可以設置成setTimeout(handler,0)(異步操作不在討論范圍內)
以上哪有寫的不對的地方歡迎指正學習。^3^
歡迎轉載
轉載注明原創地址:http://www.cnblogs.com/Jersen/p/4887225.html