我们知道JavaScript的代码基本都是瞬间执行完的,如果想在一定的时间后再去做某些事情,或者说隔一段时间重复的去做某些事情,那就需要用到定时器
9.01 - setInterval(fn|string, ms[, arg1,arg2,...])
循环定时器,每隔一段时间重复的执行一个函数
使用方法
参数:
fn | string:需要执行的函数,或者代码字符串
ms:重复一次的间隔时间(毫秒数)
arg:向方法内部传递的参数
代码案例
每隔1s打印一次"hello world~"
setInterval(function(){console.log("hello world~");},1000);
参数的使用
function fn(a,b,c){ console.log(a+b+c);// 每秒输出一次 6 } setInterval(fn,1000,1,2,3);
相关的东西
切换窗口卡顿
fn参数的作用域默认为全局作用域
执行的函数中如果有回调函数或者阻塞的代码时,不会等待这类代码执行完毕而直接开始下一轮函数的执行
var ms = 500, endTime = new Date(); setInterval(fn,ms); function fn(){ // 输出本次与上一次fn执行的时间间隔 console.log(new Date() - endTime); // 循环阻塞代码的(阻塞的时间大于定时器执行一轮的时间间隔) while(new Date()-endTime <= ms*2 ){}; // 更新本次代码执行的时间 endTime = new Date(); };
9.02 - setTimeout(fn|string, ms[, arg1,arg2,...])
单次定时器,规定时间过后执行一次函数
使用方法
参数:(略)
代码案例:
界面加载后 2s 弹出一次窗口
setTimeout(function(text){ alert(text); },2000,"hello world!");
循环调用
setTimeout 可以通过循环调用的方式实现和 setInterval 一样的间隔一段执行一次函数的效果,并且可以解决代码阻塞的问题
var
ms = 500,
endTime = new Date();
setTimeout(fn,ms);
function fn(){
console.log(new Date() - endTime);
while(new Date()-endTime <= ms*2 ){};
endTime = new Date();
// 循环调用
setTimeout(fn,ms);
};
// 封装
function timer(){
var
argArr = Array.prototype.slice.call(arguments),
args = argArr.splice(2),
off = true;
setTimeout(function fn_(){
if(off){
argArr[0].apply(window,args);
setTimeout(fn_,argArr[1]);
}
},argArr[1]);
return function(){
off = false;
}
}
9.03 - requestAnimationFrame(callback)
请求动画框架,这个框架的使用方式与 setTimeout 非常类似,区别在于这个方法是H5中新增的专门为了动画而设计的,有固定的执行频率
使用语法
参数:
callback:需要执行的回调函数
代码案例:
var n = 0; function fn(){ document.title = n++; requestAnimationFrame(fn); } requestAnimationFrame(fn);
相关的东西
动画框架的执行间隔固定为每秒60帧左右
当浏览器的窗口切换之后会暂停渲染,不会卡顿
兼容处理
window.requestAnimationFrame = window.requestAnimationFrame || function(fn){
setTimeout(function(){
fn && fn();
},1000/60);
}
9.04 - 清除定时器
clearInterval(idNum) / clearTimeout(idNum)
代码案例
var n = 0,timer = null; timer = setInterval(function(){ console.log( n++ ); },1000); // 点击document的时候清除定时器 document.onclick = function(){ clearInterval(timer); alert("清除了定时器:" + timer); }
var timer = setTimeout(function(){ console.log( "我执行了哟~" ); },1000); // 点击document的时候清除定时器 document.onclick = function(){ clearInterval(timer); alert("清除了定时器:" + timer); }
定时器的返回值
实际上定时器的返回值是一个用于标识该定时器的ID值,具有唯一性但不一定有规律,我们可以通过这个ID值传递给清除定时器的函数来清除对应的定时器
cancelAnimationFrame(globalID)
代码案例
var n = 0,idNum; (function fn(){ document.title = n++; idNum = requestAnimationFrame(fn); })(); // 点击的时候清除 document.onclick = function(){ cancelAnimationFrame(idNum); }
9.05 - 定时器其他相关
定时器的队列
定时器在被调用的时候并不会立即执行,而是会被排列在一个等待执行的队列中,等待所有的同步代码执行完成之后再根据顺序执行队列之中的定时器
看下边的列子
setInterval(function(){
console.log("a");
},100);
console.log("b");
setTimeout(function(){
console.log("c");
},0);
console.log("d");
// 输出顺序?
运动框架
元素的某些值改变的时候,比如外边距,宽度,定位值等等可以通过定时器或者动画框架写一个插件,进行一个值的渐变效果
速度版
<div id="box"></div> <script> move(box,["width",100],1); function move(obj,attrArr,speed,callback){ /* 参数说明 obj:dom节点 attrArr:改变的属性与结果值 数组格式 ==> ["width",200] speed:改变的速度 callback:回调函数 */ // 初始设置值 attrArr[1] = parseFloat(attrArr[1]); var val = parseFloat(getStyle(obj)[attrArr[0]]),// 获取初始值 sValue = [val,val<=attrArr[1]?speed:-speed],// 判断加值还是减值 timer = setInterval(function(){ sValue[0] += sValue[1]; // 判断是否已经到达目标值 if( sValue[1]>=0? sValue[0]/attrArr[1]: attrArr[1]/sValue[0] >= 1 ){ clearInterval(timer); sValue[0] = attrArr[1]; callback && callback(); } obj.style[attrArr[0]] = sValue[0] + "px"; },1000/60); } // 样式获取兼容 function getStyle(obj){ return obj.currentStyle || getComputedStyle(obj); } </script>
时间版
<div id="box" style="width:100px;height:100px;background-color:red;"></div> <script> var attrJson = { width:300, height:300, opacity:1 }; function callback(){ console.log(this); } move(box,attrJson,1000,callback); function move(obj,attrJson,time,callback){ /* 参数说明 obj:dom对象 attJson:过渡属性 json time:过渡完成的毫秒数 callback:回调函数 */ // 获取初始值 var sAttr = {}, eAttr = {}; for(var k in attrJson){ sAttr[k] = parseFloat(css(obj)[k]); eAttr[k] = parseFloat(attrJson[k]); } // 初始化变量 var sTime = new Date(), // 初始时间 nTime, // 时间差 s, // 速度 value, // 当前值 off = false; // 定时开关 // 动画跑起 (function animat(){ nTime = new Date() - sTime; off = nTime/time>=1; // 时间差与目标时间比是否大于 1 for(var k in attrJson){ s = sAttr[k] + (eAttr[k] - sAttr[k])*nTime/time; // s/t = s总/t总 if(off)s= eAttr[k]; // 达到目标值后修正目标值 css(obj,[k,s + (k==="opacity"?"":"px")]);// 设置当前值 } if(off)callback && callback.call(obj); // 回调函数 !off && setTimeout(animat,1000/60); })(); // 样式的获取与设置 function css(dom,attrSetArr){ // 判断是否为设置属性 if(attrSetArr === undefined){ return dom.currentStyle || getComputedStyle(dom); } // 兼容低版本IE 的 opacity if(attrSetArr[0] === "opacity" && dom.currentStyle){ attrSetArr = ["filter","alpha(opacity="+(attrSetArr[1]*100)+")"]; } dom.style[attrSetArr[0]] = attrSetArr[1]; } } </script>