淺談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和記憶體使用量。