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

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

定義和用法

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

語法

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

 

 

提示和註釋

提示:setTimeout() 只執行 code 一次。若是要屢次調用,請使用 setInterval() 或者讓 code 自身再次調用 setTimeout()。java

以上定義來源於w3school.comajax

 

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

相關文章
相關標籤/搜索