在写h5游戏时经常需要使用定时刷新页面实现动画效果,比较常用即settimeout()以及setinterval()
settimeout() 方法用于在指定的毫秒数后调用函数或计算表达式,而setinterval()则是在每隔指定的毫秒数循环调用函数或表达式,直到clearinterval把它清除。也就是说settimeout()只执行一次,setinterval()可以执行多次。两个函数的参数也相同,第一个参数是要执行的code或句柄,第二个是延迟的毫秒数
timeoutid:定时器id号,它可以在cleartimeout()函数中被用来清除定时器。
code:一个被执行的代码串或函数
millisec:延迟的时间,单位毫秒。如果没有指定,默认为0
settimeout() 方法用于在指定的毫秒数后调用函数或计算表达式
注:调用过程中,可以使用cleartimeout(id_of_settimeout)终止
window.settimeout或settimeout,两个写法基本一样,只不过window.settimeout将settimeout函数作为全局window对象的一个属性来引用
window.settimeout方法调用函数有两种方法:
无论window.settimeout还是window.setinterval,在使用函数名作为调用句柄时都不能带参数,而在许多场合必须要带参数,这就需要想方法解决。例如对于函数hello(_name),它用于针对用户名显示欢迎信息: var username="jack";
这时,如果企图使用以下语句来使hello函数延迟3秒执行是不可行的:
这将使hello函数立即执行,并将返回值作为调用句柄传递给settimeout函数,其结果并不是程序需要的。而使用字符串形式可以达到想要的结果:
如果在延时期限到达之前取消演示执行,可以使用window.cleartimeout(timeoutid)方法
这样,如果要取消显示,只需单击页面任何一部分,就执行了window.cleartimeout方法,使得超时操作被取消
除了前两个参数,settimeout还允许添加更多的参数。它们将被传入推迟执行的函数
上面代码中,settimeout共有4个参数。最后两个参数,将在1000毫秒之后回调函数执行时,作为回调函数的参数。
ie 9.0以下版本,只允许settimeout有两个参数。这时有三种解决方法,第一种是自定义settimeout,使用apply方法将参数输入回调函数;第二种是在一个匿名函数里面,让回调函数带参数运行,再把匿名函数输入settimeout;第三种使用bind方法,把多余的参数绑定在回调函数上面,生成一个新的函数输入settimeout
除了参数问题,settimeout还有一个需要注意的地方:被settimeout推迟执行的回调函数是在全局环境执行,这有可能不同于函数定义时的上下文环境
上面代码输出的是1,而不是2,这表示回调函数的运行环境已经变成了全局环境
再看一个不容易发现错误的例子
上面代码只会显示undefined,因为等到user.sayhi执行时,它是在全局对象中执行,所以this.login取不到值。为了防止出现这个问题,一种解决方法是将user.sayhi放在函数中执行
user.sayhi是在函数作用域内执行,而不是在全局作用域内执行,所以能够显示正确的值
另一种更通用的解决方法,则是采用闭包,将this与当前运行环境绑定
上面代码中,settimeout指定的函数中的this,总是指向定义时所在的dom节点
setinterval函数的参数及用法和settimeout函数一样,不同的是,setinterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式
我们定义一个定时器timer,使用setinterval()每隔1秒调用一次timego()。这样timego会执行10次,每次数字tt会减1,直到为0。那么如果想停止定时器,可以使用以下代码:
与settimeout一样,除了前两个参数,setinterval方法还可以接受更多的参数,它们会传入回调函数
setinterval指定的是,“开始执行”之间的间隔,因此实际上,两次执行之间的间隔会小于setinterval指定的时间。假定setinterval指定,每100毫秒执行一次,每次执行需要5毫秒,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始
上面代码每隔2000毫秒跳出一个alert对话框。如果用户一直不点击“确定”,整个浏览器就处于“堵塞”状态,后面的执行就一直无法触发,会累积起来。举例来说,第一次跳出alert对话框后,用户过了6000毫秒才点击“确定”,那么第二次、第三次、第四次执行将累积起来,它们之间不会再有等待间隔。
为了确保两次执行之间有固定的间隔,可以不用setinterval,而是每次执行结束后,使用settimeout指定下一次执行的具体时间。上面代码用settimeout,可以改写如下
<code>cleartimeout(对象)</code> 清除已设置的<code>settimeout</code>对象;<code>clearinterval(对象)</code> 清除已设置的<code>setinterval</code>对象
其实settimeout()也可以实现每隔一段时间重复执行某个函数,所以在js中settimeout 和 setinterval 都经常被用来做网页上的定时器,允许为它指定一个毫秒数作为间隔执行的时间。当被启动的程序需要在非常短的时间内运行,我们就会给她指定一个很小的时间数,或者需要马上执行的话,我们甚至把这个毫秒数设置为0,但事实上,settimeout有一个最小执行时间,当指定的时间小于该时间时,浏览器会用最小允许的时间作为settimeout的时间间隔,也就是说即使我们把settimeout的毫秒数设置为0,被调用的程序也没有马上启动
很多人会理所当然的认为for循环会分别打印出1,2,3. 但是事实不是这样的,会输出3次4. 要理解为什么会打印三次4,我们先来理解settimeout这个函数吧,很多人会认为上面的settimeout的意思是这样的:在100毫秒后执行settimeout的回调函数,其实这样的理解是有误的,其实settimeout与setinterval真正的含义如下:
settimeout:在指定的毫秒数后,将定时任务处理的函数添加到执行队列的队尾
setinterval:按照指定的周期(以毫秒数计时),将定时任务处理函数添加到执行队列的队尾
settimeout与setinterval都是异步的,所以我们现在可以来理解下上面循环为什么一直都是4呢?其实调用settimeout时候,会有一个延时事件排入队列,然后settimeout调用之后的那行代码运行,接着是再下一行代码,直到再也没有任何代码了,javascript虚拟机才会问,队列里还有吗?如果队列中至少有一个事件适合于触发,比如上面的settimeout函数,则会调用settimeout那个函数。所以上面的代码先for循环,循环结束,而 i === 4一直递增,直到不再满足i<=3为止。所以就打印了3个4
运行结果是:先打印出 “我是新来的,我先执行”这句代码,接着打印”打印我,我是异步执行的”代码
settimeout的作用是将代码推迟到指定时间执行,如果指定时间为0,即settimeout(f,0),那么会立刻执行吗?
答案是不会。因为上一段说过,必须要等到当前脚本的同步任务和“任务队列”中已有的事件,全部处理完以后,才会执行settimeout指定的任务。也就是说,settimeout的真正作用是,在“任务队列”的现有事件的后面再添加一个事件,规定在指定时间执行某段代码。settimeout添加的事件,会在下一次event loop执行
settimeout(f,0)将第二个参数设为0,作用是让f在现有的任务(脚本的同步任务和“任务队列”中已有的事件)一结束就立刻执行。也就是说,settimeout(f,0)的作用是,尽可能早地执行指定的任务
上面代码说明,settimeout(f,0)必须要等到当前脚本的所有同步任务结束后才会执行。
0毫秒实际上达不到的。根据html 5标准,settimeout推迟执行的时间,最少是4毫秒。如果小于这个值,会被自动增加到4。另一方面,浏览器内部使用32位带符号的整数,来储存推迟执行的时间。这意味着settimeout最多只能推迟执行2147483647毫秒(24.8天),超过这个时间会发生溢出,导致回调函数将在当前任务队列结束后立即执行,即等同于settimeout(f,0)的效果
比如,网页开发中,某个事件先发生在子元素,然后冒泡到父元素,即子元素的事件回调函数,会早于父元素的事件回调函数触发。如果,我们先让父元素的事件回调函数先发生,就要用到settimeout(f, 0)
面代码在点击按钮后,先触发回调函数a,然后触发函数c。在函数a中,settimeout将函数b推迟到下一轮loop执行,这样就起到了,先触发父元素的回调函数c的目的了
用户自定义的回调函数,通常在浏览器的默认动作之前触发。比如,用户在输入框输入文本,keypress事件会在浏览器接收文本之前触发。因此,下面的回调函数是达不到目的的
上面代码想在用户输入文本后,立即将字符转为大写。但是实际上,它只能将上一个字符转为大写,因为浏览器此时还没接收到文本,所以this.value取不到最新输入的那个字符。只有用settimeout改写,上面的代码才能发挥作用
上面代码将代码放入settimeout之中,就能使得它在浏览器接收到文本之后触发
由于settimeout(f,0)实际上意味着,将任务放到浏览器最早可得的空闲时段执行,所以那些计算量大、耗时长的任务,常常会被放到几个小部分,分别放到settimeout(f,0)里面执行
上面代码有两种写法,都是改变一个网页元素的背景色。写法一会造成浏览器“堵塞”,而写法二就能就不会,这就是settimeout(f,0)的好处
另一个使用这种技巧的例子是,代码高亮的处理。如果代码块很大,就会分成一个个小块,写成诸如settimeout(highlightnext, 50)的样子,进行分块处理