setTimeout和setInterval的区别以及如何写出效率高的倒计时
1.setTimeout和setInterval都屬于js中的定時器,可以規定延遲時間再執行某個操作,不同的是setTimeout在規定時間后執行完某個操作就停止了,而setInterval則可以一直循環執行下去。
下面介紹一下兩種定時器的語法:
setTimeout(expression,milliseconds) 以及 setInterval(expression,milliseconds)
其中 expression是將要執行的某一項操作,而milliseconds則是延遲時間,expression可以是一個將要執行的函數名,也可以是一個字符串
比如:
1 function fun(){
2 alert('hello');
3 }
4 setTimeout(fun,1000); //參數是函數名
5 setTimeout('fun()',1000); //參數是字符串
6 setInterval(fun,1000);
7 setInterval('fun()',1000);
在上面代碼中,無論是setTimeout還是setInterval,在使用函數名作為調用句柄時不能帶參數,使用字符串調用時可以帶參數,如:setTimeout('fun(name)',1000);
但是有些場合會要求必須使用函數名作為調用句柄,此時可以用另一種方法帶參數:
方法一:
function fun(name){
alert('hello'+' ' +name);
}
function _fun(name){
return function(){
fun(name);
}
}
setTimeout(_fun('Tom'),1000); //參數是函數名
方法二:
不用單獨再定義一個函數,直接將函數調用放在一個函數里面,可以使用函數名作為調用句柄:
function fun(name){
alert('hello'+' ' +name);
}
setTimeout(function(){
fun('Tom');
},1000); //參數是函數名
setInterval使用方式一樣,就不再多寫了。
在以上代碼中,setTimeout和setInterval的區別就是 setTimeout延遲一秒彈出'hello',之后便不再運行;而setInterval則會每隔一秒鐘彈出'hello',直至用clear來清除
清除定時器的語法:
定時器會返回一個id,只要對這個id進行清除的操作即可:
1 function fun(){
2 alert('hello');
3 }
4 var t1 = setTimeout(fun,1000);
5 var t2 = setInterval(fun,1000);
6 clearTimeout(t1);
7 clearInterval(t2);
2. 用setTimeout實現setInterval的功能
雖然setTimeout只在延時時間后執行一次,但是我們可以使用遞歸調用的方法實現循環調用,實現類似setInterval的功能,例:
1 function fun(){
2 alert('hello');
3 setTimeout(fun,1000);
4 }
5 fun();
以上代碼的功能是每隔一秒鐘頁面便彈出“hello”,相當于setInterval的循環間隔調用。
但是即使可以實現同樣的功能,兩種定時器也還是有運行方面的差別:
比如延時1s執行函數fun(),但是函數內部的操作執行需要的時間是2S,由于JavaScript是單線程的,那在這次執行完之前,下一次的循環便被阻塞了,處在排隊的狀態,當此次操作執行完以后才會執行處在排隊狀態的操作,
但是排隊的序列太多,阻塞結束以后只能執行一個,這樣會造成性能的浪費,
所以在這樣的情況下,使用setTimeout遞歸調用實現循環的方法便顯得很方便,它不會發生阻塞的狀況
比如函數內部的執行需要2S,那setTimeout會等2S執行完以后才去遞歸調用,也就是說整個一次循環需要3S的時間。
但是setTimeout又不如setInterval執行的精確,所以在不同情況下可以選擇不同的定時器以達到最好的效果。
3.如何寫出一個高效的倒計時
身為小白的我目前能寫出來的只是能實現該需求的最低級的代碼OTZ
1 var t,num = 60;
2 function timeDown(){
3 num--;
4 num = num < 10 ? ('0'+num) : (num+''); // 左側補0操作
5 document.getElementById('demo').innerHTML = num;
6 t = setTimeout(function(){
7 timeDown();
8 },1000);
9 if(num <= 0){
10 clearTimeout(t);
11 }
12 }
13 timeDown();
以上代碼是用setTimeout遞歸調用外層函數實現的
下面是用setInterval實現的方法:
1 var t,num = 5;
2 function timeDown(){
3 num--;
4 num = num < 10 ? ('0'+num) : (num+'');
5 document.getElementById('demo').innerHTML = num;
6 if(num <= 0){
7 window.clearInterval(t);
8 }
9 }
10 t = setInterval(timeDown,1000);
以上用兩種定時器寫出的代碼都是運用的最基本的實現方式,也是我現在的經驗和水平能寫出來的,
前段時間在掘金社區看到一個很厲害的由淺入深的寫倒計時的方法,現在粘貼過來跟我的對比一下,簡直無地自容OTZ
首先是左側補0的幾種方法:
//方法一:大于10的返回值的類型是number類型,沒有做轉換
function leftPad(i){
if(i<10){
i = "0" + i;
}
return i;
}
//方法二:對上一種方法做了彌補,但是沒有考慮到復數的情況
function leftPad(i){
return i < 10 ? '0'+i : i+'';
}
//方法三:對返回值類型做了轉換,同時也考慮到了負數的情況,這也是目前我的水平能想到的寫法了。。
function leftPad(n){
var n = parseInt(n, 10);
return n > 0 ? n <= 9 ? ('0'+n) : (n+'') :'00';
}
//下面兩種方法我其實就有點看不懂了,不過還是先貼在這里,等我學會了再回來看看
function leftPad(n, len){
len = len || 2;
n = n + '';
var diff = len - n.length;
if (diff > 0) {
n = new Array(diff + 1).join('0') + n;
}
return n;
}
function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}
然后是倒計時的代碼:
方法一:
單例模式,簡單方便好理解,缺點是每次init都會拿一個新定時器,性能不好。繼承和擴展能力一般,無法獲取實例屬性,導致了執行狀態都是不可見的。
var CountDown = {
$ : function(id){/*id選擇器*/},
init :function(startTime,endTime,el){/*執行定時器入口,使用setTimeout調用_timer*/},
_timer : function(startTime,endTime,el){/*私有方法,處理時間參數等具體業務*/}
}
CountDown.init("","2016,04,23 9:34:44","countdown1");
方法二:
標準的原型構造器寫法,簡單方便好理解,確定是每次都拿一個新定時器,實例增多后性能同樣不好,按道理setTime,leftPad等方法都可以通過繼承來實現,方便擴展和復用,
prototype上的方法均為輔助方法,按理不應該被外部調用,這里應該封裝為私有方法或者前綴+_,優點可以通過實例拿到相關倒計時屬性,可以對實例再做擴展操作。
function Countdown(elem, startTime, endTime) {
this.elem = elem;
this.startTime = (new Date(startTime).getTime()) ? (new Date(startTime).getTime()) : (new Date().getTime());
this.endTime = new Date(endTime).getTime();
}
Countdown.prototype = {
SetTime: function() {},
leftPad: function(n) {},
DownTime: function() {}
}
var test = new Countdown("time", "2016/1/30,12:20:12", "2017/1/30,12:20:12");
test.SetTime();
方法三:
優點:這里的countdown是一個比較簡單的工廠模式實現,實現了一個統一的create方法,create方法上調用了style這個屬性上擴展的樣式(style1-3)實現,
create方法返回的是一個獨立的新實例,并統一擴展了go方法,go方法里統一創建定時器并掛載到timer屬性,在這里我們也就等同擁有了修改和控制每個工廠造出來的單例的能力,
樣式做到了可擴展,leftPad,timeToSecond也可以方便通過一個utils對象來進行繼承。
缺點:沒有考慮到上面提到的setTimeout和setInterval的區別,也沒有時間校驗機制,在性能方面考慮不多。
var countdown = {};
countdown.leftPad = function(n, len) {};
countdown.timeToSecond = function(t) {};
/**
* 倒計時工廠
* @param {[object]} obj 倒計時配置信息
* @return {[object]} 返回一個倒計時對象
*/
countdown.create = function(obj) {
var o = {};
o.dom = document.getElementById(obj.id);
o.startMS = +new Date(obj.startTime || 0);
o.endMS = +new Date(obj.endTime || 0);
obj.totalTime && (o.totalTime = countdown.timeToSecond(obj.totalTime));
var newCountdown = new countdown.style[obj.style](o);
newCountdown.go = function(callback) {
callback && (newCountdown.callback = callback);
newCountdown.render();
clearInterval(newCountdown.timer);
newCountdown.timer = setInterval(newCountdown.render, 1000);
};
return newCountdown;
};
countdown.style.style1 = function(obj) {
this.dom = obj.dom;
this.startMS = obj.startMS;
this.endMS = obj.endMS;
var _this = this;
this.render = function() {
var currentMS = +new Date();
var diff = (_this.endMS - currentMS) / 1000;
var d = parseInt(diff / 60 / 60 / 24);
d = countdown.leftPad(d, 3);
d = d.replace(/(\d)/g, '<span>$1</span>');
_this.dom.innerHTML = '距離國慶節還有:' + d + '天';
if (currentMS > _this.endMS) {
clearInterval(_this.timer);
if (_this.callback) {
_this.callback();
} else {
_this.dom.innerHTML = '國慶節倒計時結束';
}
}
};
};
countdown.style.style2 = function(obj) {};
countdown.style.style3 = function(obj) {};
countdown.create({id:"clock3",totalTime:'82:23',style:'style1'}).go(function(){alert('It is over');});
以上是我在社區里看到的前幾個例子,后面的幾個例子已經是我看不懂的階段了。。。所以就不貼在這里了,先保存記錄,然后再慢慢學習
自己的程序員之路還有很遠要走。。。
by新手小白的紀錄
總結
以上是生活随笔為你收集整理的setTimeout和setInterval的区别以及如何写出效率高的倒计时的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IPv6 地址数量有多少,能够分配到地球
- 下一篇: 理解GBN协议