JavaScript 關於setTimeout與setInterval的小研究

說明

在開發功能「軌跡播放」時,遇到了一個狀況。
原先同事已經開發了一版,此次有個新功能:點擊線上任意一點後能夠從點擊處從新播放。
看了一下原來的版本,發現同時使用了setTimeout和setInterval,二者配合實現點線播放。
簡單結構以下html

function test() {
            setInterval(function () {
                console.log("interval");
                                //省略插值方法獲得arr
                                (...)
                play(arr);
            }, 2000);
        }
        function play(arr) {
            setTimeout(function () {
                play(arr);
                console.log("setTimeout");
            }, 40);
        }

我以爲這個結構欠妥,兩個定時器配合一定會出現失誤!所以重構了一版,將兩個定時器改成一個,用setInterval解決。
可是此時我並不知道欠妥欠在什麼地方,缺少理論支持,如今閒下來仔細研究了一下ajax

找問題

在仔細研究了舊版本後,我先把舊版本結構扒了出來,排除其餘因素,本身模擬了一個簡單版(就是上面的代碼)
setTimeout:在執行時,是在載入後延遲指定時間後,去執行一次表達式,僅執行一次
setInterval:在執行時,它從載入後,每隔指定的時間就執行一次表達式瀏覽器

  • 實驗一:在使用setInterval和setTimeout方法上,並無什麼問題,決定跑一下,結果以下

file

從結果得出兩點結論網絡

  1. setTimeout與setInterval並非50倍速度配合運行着
  2. 兩次interval間,timeout運行的次數愈來愈多,代表setInterval運行間隔愈來愈長,延遲愈來愈大
  • 實驗二:加一點人工干預再執行
function test() {
            setInterval(function () {
                console.log("interval");
                play();
            }, 2000);
        }
        function play() {
                    //延遲執行
            for (var i = 0; i < 100000000; i++) {
                
             }
            setTimeout(function () {
                play();
                console.log("setTimeout");
            }, 40);
        }

file

從結果得出兩點結論多線程

  1. setInterval可能會隨函數處理時間,減小間隔
  2. 推測,由於Javascript是單線程的,setInterval和setTimeout是放隊列裏執行的,很容易受到回調事件影響
  • 實驗三:拖動縮放瀏覽器

file

從結果得出結論函數

  1. 當瀏覽器標籤切換到其餘頁面,或者瀏覽器最小化,會影響計時器,二者會出現間隔減少

涉及知識點

綜上實驗結果,網上搜集了一些資料能說明問題:線程

  1. JavaScript是單線程,可是瀏覽器是多線程,Javascript是瀏覽器多線程中的一個線程。(圖參考自:http://www.javashuo.com/article/p-ttwiqhax-ga.html

file

  1. Javascript會把執行的回調函數、瀏覽器的觸發事件、UI渲染事件,先放到隊列中,隊列根據先進先出的規則,依次執行他們,當執行到隊列中的setInterval時很難保證其與setTimeout同步關係還保持。
  2. setInterval無視代碼錯誤:代碼報錯,可是setInterval依舊會按時執行,不會中斷。
  3. setInterval無視網絡延遲:若是調用ajax或其餘服務,他不會管是否返回回調,會繼續按時執行。
  4. setInterval不保證執行:由於setInterval會定時執行,若是函數邏輯很長,間隔時間內執行不完,後續方法會被拋棄。
  5. 會受瀏覽器狀態影響,tab切換、最小化等

解決方案

在作軌跡播放時,setInterval的延遲還在可接受範圍以內,可是網上給出的最佳解決方案是用setTimeout作。
setTimeout只會執行一次,在執行完成後,從新啓動新的Timeout,時間runtime計算設置爲差時,減小出現間隔愈來愈大的狀況code

function test() {
                    //runTime,計算差時
                        runTime = 1000 - 執行耗時;
            setTimeout(callback, runTime);
        }
        setTimeout(test, 1000);
相關文章
相關標籤/搜索