JavaScript中的定时器

定时器javascript

一、setTimeoutcss

这个方法用于在指定的毫秒数以后执行某个函数,返回定时器的句柄html

混合的 setTimeout()方法设置一个定时器,该定时器在定时器到期后执行一个函数或指定的一段代码。java

语法

let timeoutID = window.setTimeout(func[, delay, param1, param2, ...]); let timeoutID = scope.setTimeout(code[, delay]); let timeoutID = window.setTimeout(function, milliseconds);

说明:node

  • timeoutID 是该延时操做的数字ID, 此ID随后能够用来做为window.clearTimeout方法的参数.
  • func 是你想要在delay毫秒以后执行的函数.
  • code 在第二种语法,是指你想要在delay毫秒以后执行的代码字符串 (使用该语法是不推荐的, 不推荐的缘由和eval()同样)
  • delay 是延迟的毫秒数 (一秒等于1000毫秒),函数的调用会在该延迟以后发生。若是省略该参数,delay取默认值0。实际的延迟时间可能会比 delay 值长,缘由请查看下面的备注。

须要注意的是,IE9 及更早的 IE 浏览器不支持第一种语法中向延迟函数传递额外参数的功能。若是你想要在IE中达到一样的功能,你必须使用一种兼容代码api

备注: 在Gecko 13以前 (Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10), Gecko会给延迟函数传递一个额外的参数,该参数代表了这次延迟操做实际延迟的毫秒数.如今,这个非标准的参数已经不存在了.浏览器

例子

下文的例子在网页中设置了两个简单的按钮,以触发 setTimeout 和 clearTimeout 方法:按下第一个按钮会在 2s 后显示一个警告对话框,并将这次 setTimeout 的延时 ID 保存起来。按下第二个按钮能够取消此次延时调用行为。app

HTML 内容

<p>Live Example</p>
<button onclick="delayedAlert();">Show an alert box after two seconds</button>
<p></p>
<button onclick="clearAlert();">Cancel alert before it happens</button>

JavaScript 内容

var timeoutID; function delayedAlert() { timeoutID = window.setTimeout(slowAlert, 2000); } function slowAlert() { alert("That was really slow!"); } function clearAlert() { window.clearTimeout(timeoutID); }

回调参数

若是你须要向你的回调函数内传递一个参数, 并且还须要兼容IE9及之前的版本, 因为IE不支持传递额外的参数 (setTimeout() 或者 setInterval()都不能够) ,但你能够引入下面的兼容代码.该代码能让IE也支持符合HTML5标准的定时器函数.函数

/*\ |*| |*| IE-specific polyfill which enables the passage of arbitrary arguments to the |*| callback functions of javascript timers (HTML5 standard syntax). |*| |*| https://developer.mozilla.org/en-US/docs/DOM/window.setInterval |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, param1, param2, ...]); |*| var intervalID = window.setInterval(code, delay); |*| \*/
 
if (document.all && !window.setTimeout.isPolyfill) { var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setTimeout.isPolyfill = true; } if (document.all && !window.setInterval.isPolyfill) { var __nativeSI__ = window.setInterval; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setInterval.isPolyfill = true; }

IE Only Fix

若是你须要单独的针对IE9及以前浏览器的 hack 写法,你可使用 JavaScript 条件注释:动画

/*@cc_on // conditional IE < 9 only fix @if (@_jscript_version <= 9) (function(f){ window.setTimeout =f(window.setTimeout); window.setInterval =f(window.setInterval); })(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c.apply(this,a)},t)}}); @end @*/
 

或者使用更加清晰的 IE HTML 条件注释:

<!--[if lte IE 9]><script> (function(f){ window.setTimeout =f(window.setTimeout); window.setInterval =f(window.setInterval); })(function(f){return function(c,t){ var a=[].slice.call(arguments,2); return f(function(){c.apply(this,a)},t)} }); </script><![endif]-->

 

另外一种方法是使用匿名函数包裹你的回调函数,这种方式要消耗更多资源:

var intervalID = setTimeout(function() { myFunc("one", "two", "three"); }, 1000); 

此外,也可以使用 function's bind

setTimeout(function(arg1){}.bind(undefined, 10), 1000);

关于"this"的问题

当你向 setTimeout() (或者其余函数也行)传递一个函数时,该函数中的this会指向一个错误的值.

解释

setTimeout()调用的代码运行在与所在函数彻底分离的执行环境上. 这会致使,这些代码中包含的 this 关键字会指向 window (或全局)对象,这和所指望的this的值是不同的.查看下面的例子:

myArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) { alert(arguments.length > 0 ? this[sProperty] : this); }; myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1,5 seconds // let's try to pass the 'this' object
setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error

正如你所看到的同样,咱们没有任何方法将this对象传递给回调函数.

解决方案

一个可用的解决 "this" 问题的方法是使用两个非原生的setTimeout() 和 setInterval() 全局函数代替原生的.该非原生的函数经过使用Function.prototype.call 方法激活了正确的做用域.下面的代码显示了应该如何替换:

// Enable the passage of the 'this' object through the JavaScript timers
 
var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () { vCallback.apply(oThis, aArgs); } : vCallback, nDelay); }; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () { vCallback.apply(oThis, aArgs); } : vCallback, nDelay); };

备注: 这两个替换也让 IE支持了符合 HTML5 标准的定时器函数。因此也能做为一个 polyfills

新特性检测:

myArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) { alert(arguments.length > 0 ? this[sProperty] : this); }; setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but...
setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2,5 seconds

针对这个问题并无原生的解决方案。

注:JavaScript 1.8.5 引入了 Function.prototype.bind() 方法,该方法容许显式地指定函数调用时 this 所指向的值 。该方法能够帮助你解决 this 指向不肯定的问题。

使用bind的例子:

myArray = ["zero", "one", "two"]; myBoundMethod = (function (sProperty) { console.log(arguments.length > 0 ? this[sProperty] : this); }).bind(myArray); myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds

备注

你可使用 window.clearTimeout()来取消延迟操做。若是你但愿你的代码被重复的调用 (好比每 N 毫秒一次),考虑使用 window.setInterval()

记住这一点:只有当调用setTimeout()的线程中止后,函数或代码段才能继续执行。

传递字符串字面量

setTimeout()传递一个字符串而不是函数会遭受到与使用eval同样的风险.

// 推荐
window.setTimeout(function() { alert("Hello World!"); }, 500); // 不推荐
window.setTimeout("alert(\"Hello World!\");", 500);

字符串会在全局做用域内被解释执行,因此当setTimeout()函数执行完毕后,字符串中的变量不可用.

二、 setInterval

这个方法用于循环地执行某个函数,返回定时器的句柄

语法

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

参数

  • intervalID 是此重复操做的惟一辨识符,能够做为参数传给clearInterval()
  • func 是你想要重复调用的函数。
  • code 是另外一种语法的应用,是指你想要重复执行的一段字符串构成的代码(使用该语法是不推荐的,不推荐的缘由和eval()同样)。
  • delay 是每次延迟的毫秒数 (一秒等于1000毫秒),函数的每次调用会在该延迟以后发生。和setTimeout同样,实际的延迟时间可能会稍长一点。

须要注意的是,IE不支持第一种语法中向延迟函数传递额外参数的功能.若是你想要在IE中达到一样的功能,你必须使用一种兼容代码 

备注: 在Gecko 13以前 (Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10), Gecko会给延迟函数传递一个额外的参数,该参数代表了这次延迟操做实际延迟的毫秒数。如今,这个非标准的参数已经不存在了。

重复调用一个函数或执行一个代码段,以固定的时间延迟在每次调用之间。返回一个 intervalID。

例1:基本用法

var intervalID = window.setInterval(animate, 500);

例2:两种颜色的切换

下面的例子里会每隔一秒就调用函数flashtext()一次,直至你经过按下Stop按钮来清除本次重复操做的惟一辨识符intervalID

<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title>setInterval/clearInterval example</title>
<script type="text/javascript">
var nIntervId; function changeColor() { nIntervId = setInterval(flashText, 500); } function flashText() { var oElem = document.getElementById("my_box"); oElem.style.color = oElem.style.color == "red" ? "blue" : "red"; } function stopTextColor() { clearInterval(nIntervId); } </script>
</head>
 
<body onload="changeColor();">
<div id="my_box">
<p>Hello World</p>
</div>
<button onclick="stopTextColor();">Stop</button>
</body>
</html>

例3:打字机的效果

下面这个例子经过键入、删除和再次键入全部NodeList中的符合的特定selector的字符,以达到打字机的效果。

<!doctype html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title>JavaScript Typewriter - MDN Example</title>
<script type="text/javascript">
function Typewriter (sSelector, nRate) { function clean () { clearInterval(nIntervId); bTyping = false; bStart = true; oCurrent = null; aSheets.length = nIdx = 0; } function scroll (oSheet, nPos, bEraseAndStop) { if (!oSheet.hasOwnProperty("parts") || aMap.length < nPos) { return true; } var oRel, bExit = false; if (aMap.length === nPos) { aMap.push(0); } while (aMap[nPos] < oSheet.parts.length) { oRel = oSheet.parts[aMap[nPos]]; scroll(oRel, nPos + 1, bEraseAndStop) ? aMap[nPos]++ : bExit = true; if (bEraseAndStop && (oRel.ref.nodeType - 1 | 1) === 3 && oRel.ref.nodeValue) { bExit = true; oCurrent = oRel.ref; sPart = oCurrent.nodeValue; oCurrent.nodeValue = ""; } oSheet.ref.appendChild(oRel.ref); if (bExit) { return false; } } aMap.length--; return true; } function typewrite () { if (sPart.length === 0 && scroll(aSheets[nIdx], 0, true) && nIdx++ === aSheets.length - 1) { clean(); return; } oCurrent.nodeValue += sPart.charAt(0); sPart = sPart.slice(1); } function Sheet (oNode) { this.ref = oNode; if (!oNode.hasChildNodes()) { return; } this.parts = Array.prototype.slice.call(oNode.childNodes); for (var nChild = 0; nChild < this.parts.length; nChild++) { oNode.removeChild(this.parts[nChild]); this.parts[nChild] = new Sheet(this.parts[nChild]); } } var nIntervId, oCurrent = null, bTyping = false, bStart = true, nIdx = 0, sPart = "", aSheets = [], aMap = []; this.rate = nRate || 100; this.play = function () { if (bTyping) { return; } if (bStart) { var aItems = document.querySelectorAll(sSelector); if (aItems.length === 0) { return; } for (var nItem = 0; nItem < aItems.length; nItem++) { aSheets.push(new Sheet(aItems[nItem])); /* Uncomment the following line if you have previously hidden your elements via CSS: */
        // aItems[nItem].style.visibility = "visible";
 } bStart = false; } nIntervId = setInterval(typewrite, this.rate); bTyping = true; }; this.pause = function () { clearInterval(nIntervId); bTyping = false; }; this.terminate = function () { oCurrent.nodeValue += sPart; sPart = ""; for (nIdx; nIdx < aSheets.length; scroll(aSheets[nIdx++], 0, false)); clean(); }; } /* usage: */
var oTWExample1 = new Typewriter(/* elements: */ "#article, h1, #info, #copyleft", /* frame rate (optional): */ 15); /* default frame rate is 100: */
var oTWExample2 = new Typewriter("#controls"); /* you can also change the frame rate value modifying the "rate" property; for example: */
// oTWExample2.rate = 150;
 onload = function () { oTWExample1.play(); oTWExample2.play(); }; </script>
<style type="text/css"> span.intLink, a, a:visited { cursor: pointer; color: #000000; text-decoration: underline;
} #info { width: 180px; height: 150px; float: right; padding: 4px; overflow: auto; font-size: 12px; margin: 4px; border-radius: 5px;
  /* visibility: hidden; */
}
</style>
</head>
 
<body>
 
<p id="copyleft" style="font-style: italic; font-size: 12px; text-align: center;">CopyLeft 2012 by <a href="https://developer.mozilla.org/" target="_blank">Mozilla Developer Network</a></p>
<p id="controls" style="text-align: center;">[&nbsp;<span class="intLink" onclick="oTWExample1.play();">Play</span> | <span class="intLink" onclick="oTWExample1.pause();">Pause</span>
| <span class="intLink" onclick="oTWExample1.terminate();">Terminate</span>&nbsp;]</p> <div id="info"> Vivamus blandit massa ut metus mattis in fringilla lectus imperdiet. Proin ac ante a felis ornare vehicula. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque.
Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. In tincidunt tincidunt tincidunt.
</div> <h1>JavaScript Typewriter</h1> <div id="article"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna.

Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula
quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas,
velit erat ornare tortor, non viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, suscipit a hendrerit vitae, volutpat non ipsum.</p> <form name="myForm"> <p>Phasellus ac nisl lorem: <input type="text" name="email" /><br /> <textarea name="comment" style="width: 400px; height: 200px;">
Nullam commodo suscipit lacus non aliquet. Phasellus ac nisl lorem, sed facilisis ligula. Nam cursus lobortis placerat. Sed dui nisi, elementum eu sodales ac, placerat sit amet mauris. Pellentesque

dapibus tellus ut ipsum aliquam eu auctor dui vehicula. Quisque ultrices laoreet erat, at ultrices tortor sodales non. Sed venenatis luctus magna, ultricies ultricies nunc fringilla eget. Praesent scelerisque
urna vitae nibh tristique varius consequat neque luctus. Integer ornare, erat a porta tempus, velit justo fermentum elit, a fermentum metus nisi eu ipsum. Vivamus eget augue vel dui viverra adipiscing congue ut massa.
Praesent vitae eros erat, pulvinar laoreet magna. Maecenas vestibulum mollis nunc in posuere. Pellentesque sit amet metus a turpis lobortis tempor eu vel tortor. Cras sodales eleifend interdum.</textarea></p> <p><input type="submit" value="Send" /> </form> <p>Duis lobortis sapien quis nisl luctus porttitor. In tempor semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis
gravida nec. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elit. Donec dignissim est in quam tempor consequat. Aliquam aliquam
diam non felis convallis suscipit. Nulla facilisi. Donec lacus risus, dignissim et fringilla et, egestas vel eros. Duis malesuada accumsan dui, at fringilla mauris bibStartum quis. Cras adipiscing ultricies fermentum.
Praesent bibStartum condimentum feugiat.</p> <p>Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin mattis lobortis lobortis. Quisque accumsan faucibus erat, vel varius tortor ultricies ac.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec libero nunc. Nullam tortor nunc, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Pellentesque a nisl eu sem vehicula egestas.</p> </div> </body> </html>

倒计时:

<div class="box">
        <span class="h time">12</span>
        <span>:</span>
        <span class="m time">12</span>
        <span>:</span>
        <span class="s time">55</span>
    </div>
    <script>
        var div = document.body.children[0]; //全部的span
        var spans = div.children; var second = spans[4]; var minutes = spans[2]; console.log(minutes); //每隔1秒钟修改秒数
 setInterval(function(){ // 先获取旧的数字,自增,从新赋值
            var old = parseInt(second.innerText); var m = parseInt(minutes.innerText); old +=1; //以上是秒的逻辑,到分的逻辑
            //当秒数大于59,就满一分钟,分自增,秒重置
            if(old >59){ old = 0; //获取分的值,自增,从新赋值
 m += 1; } //小时的逻辑也是当分超过59,让小时自增1,分重置
 second.innerText = old; minutes.innerText = m; },1000); </script>

简单动画效果的实现

<!DOCTYPE html>
<html>
<head lang="zh-CN">
    <meta charset="UTF-8">
    <title></title>
    <style> * { margin: 0; padding: 0;
        } #box { width: 100px; height: 100px; background-color: #0a0;
            /*margin-left: 500px;*/
            /*通常作动画,都会使用定位,脱标定位 -- 绝对,固定*/ position: absolute; top: 200px; left: 0px;
        } .boxw { width: 100px; height: 100px; background: #cccccc; float: left;
        }
    </style>
</head>
<body>
<input type="button" value="开始运动" id="btn"/>
<div id="box"></div>
<div class="boxw"></div>
<script>
    //动画原理:每隔必定的时间,修改能控制元素位置的属性,就能达到动起来的效果,当位置到达800的时候停下来
    var curerntLeft = 0; var box = document.getElementById("box"); document.getElementById("btn").onclick = function(){ var timerId = setInterval(function(){ //每次获取当前位置,进行自增,最后从新赋值
            var step = 10;//每次移动的步长
 curerntLeft += step; box.style.left = curerntLeft + "px"; //判断当前位置是否大于等于800,若是是,就停下来
            if(curerntLeft >= 800){ clearInterval(timerId); } console.log(123456); },20);//人的肉眼通常可识别的间隔为:0.03秒 = 30毫秒
 } </script>
</body>
</html>

回调参数

若是你想经过你的函数传递回一个参数,并且还要兼容IE,因为IE不支持传递额外的参数 (setTimeout() 或者 setInterval()都不能够) ,你能够引入下面的兼容代码。该代码能让IE也支持符合HTML5标准的定时器函数。

/*\ |*| |*| IE-specific polyfill which enables the passage of arbitrary arguments to the |*| callback functions of javascript timers (HTML5 standard syntax). |*| |*| https://developer.mozilla.org/en-US/docs/DOM/window.setInterval |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, param1, param2, ...]); |*| var intervalID = window.setInterval(code, delay); |*| \*/
 
if (document.all && !window.setTimeout.isPolyfill) { var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setTimeout.isPolyfill = true; } if (document.all && !window.setInterval.isPolyfill) { var __nativeSI__ = window.setInterval; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setInterval.isPolyfill = true; }
相关文章
相关标签/搜索