setTimeout的原理及在JavaScript線程執行隊列中的位置


開發中經常使用setTimeout進行一些延遲操作。昨天突然想了解下setTimeout的handler到底在隊列中的什么位置特別好奇。今天特地來測試下。

定義和用法

setTimeout() 方法用於在指定的毫秒數后調用函數或計算表達式。

語法

setTimeout(code,millisec)
參數 描述
code 必需。要調用的函數后要執行的 JavaScript 代碼串。
millisec 必需。在執行代碼前需等待的毫秒數。

 

 

提示和注釋

提示:setTimeout() 只執行 code 一次。如果要多次調用,請使用 setInterval() 或者讓 code 自身再次調用 setTimeout()。

以上定義來源於w3school.com

 

JavaScirpt線程

先了解下瀏覽器,瀏覽器是多線程的。

  1. JavaScript引擎線程
  2. 界面渲染線程
  3. 瀏覽器事件觸發線程
  4. 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM