1. 程式人生 > >淺談setTimeout,setInterval

淺談setTimeout,setInterval

概念

setTimeout

setTimeout的用法

var timer1=scope.setTimeout(function,[delay,params]);
var timer2=scope.setTimeout(code,[delay,params]);
  • function
    function 是你想要在delay毫秒之後執行的函式。
  • code
    第二種語法,是指你想要在delay毫秒之後執行的程式碼字串 (使用該語法是不推薦的, 不推薦的原因和eval()一樣)。
  • delay 可選
    延遲的毫秒數 (一秒等於1000毫秒),函式的呼叫會在該延遲之後發生。如果省略該引數,delay取預設值0。實際的延遲時間可能會比 delay 值長,原因請檢視Reasons for delays longer than specified。
  • param1, …, paramN 可選
    可選引數。

用字串的問題:

推遲執行的程式碼以字串的形式,放入setTimeout,因為引擎內部使用eval函式,將字串轉為程式碼;

    setTimeout('console.log("2")', 1000)

這段程式碼在瀏覽器環境中會執行,在nodeJS環境中會報錯;這裡規定了setTimeout只能是函式;
這裡寫圖片描述

不推薦使用字串的原因,因為不推薦使用eval:

eval() 是一個危險的函式, 他執行的程式碼擁有著執行者的權利。如果你用eval()執行的字串程式碼被惡意方(不懷好意的人)操控修改,您可能會利用最終在使用者機器上執行惡意方部署的惡意程式碼,並導致您失去您的網頁或者擴充套件程式的許可權。更重要的是,第三方程式碼可以看到某一個eval()被呼叫時的作用域,這也有可能導致一些不同方式的攻擊。相似的Function就是不容易被攻擊的。

eval()的執行效率也普遍的比其他的替代方案慢,因為他會呼叫js解析器,即便現代的JS引擎中已經對此做了優化。

setTimeout的作用:
1. 調整事件的順序;
2. ajax防抖動
3. 分割耗時任務

setInterval

setInterval的用法

let intervalID = window.setInterval(func, delay[, param1, param2, ...]);
let intervalID = window.setInterval(code, delay);

和setTimeout的引數類似,delay是指多少秒之後迴圈執行函式,同樣的不推薦使用code;

setInterval指定的是“開始執行”之間的間隔,並不考慮每次任務執行本身所消耗的事件。因此實際上,兩次執行之間的間隔會小於指定的時間。比如,setInterval指定每100ms執行一次,每次執行需要5ms,那麼第一次執行結束後95毫秒,第二次執行就會開始。如果某次執行耗時特別長,比如需要105毫秒,那麼它結束後,下一次執行就會立即開始。

因此就會出現下面這個問題

var i = 1;
var timer = setInterval(function() {
  alert(i++);
}, 2000);

上面這段程式碼的思路是,每隔2000毫秒,執行彈出框,但是如果第一次彈出了之後,使用者沒有立即關閉視窗,而是等了好久好久,那麼後面的彈出框就會立馬彈出來了,顯然這不是我們想要的效果;

可以用setTimeout改進它,思路就是在setTimeout裡寫遞迴;

function interval(func, wait) {
        var interv = function() {
            func.call(null);
            setTimeout(interv, wait);
        };
        setTimeout(interv, wait);
    }
    interval(function() {
        console.log(2);
    }, 1000);

setInterVal的執行機制:

setInterval的執行機制是,將指定的程式碼移出本次執行,等到下一輪Event Loop時,再檢查是否到了指定時間。如果到了,就執行對應的程式碼;如果不到,就等到再下一輪Event Loop時重新判斷。

setTImeout的執行機制:

setTimeout和setInterval的執行機制是,將指定的程式碼移出本次執行,等到下一輪Event Loop時,再檢查是否到了指定時間。如果到了,就執行對應的程式碼;如果不到,就等到再下一輪Event Loop時重新判斷。這意味著,setTimeout指定的程式碼,必須等到本次執行的所有程式碼都執行完,才會執行

對於setInterval得使用,個人建議是能不用盡量不用。涉及到必須要的定時器,前文已經敘述可以使用兩個setTimeout巢狀組合來實現,並且還能規避掉一些問題得發生。涉及到要用它來製作動畫( jQuery就使用setInterval來寫動畫,也是導致其慢原因之一),更建議使用requestAnimationFrame(RAF),或者直接採用CSS來寫(如果可以的話)。
requestAnimationFrame比起setTimeout、setInterval的優勢主要有兩點:
requestAnimationFrame會把每一幀中的所有DOM操作集中起來,在一次重繪或迴流中就完成,並且重繪或迴流的時間間隔緊緊跟隨瀏覽器的重新整理頻率,一般來說,這個頻率為每秒60幀。
在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或迴流,這當然就意味著更少的的cpu,gpu和記憶體使用量。