如何在setTimeout函数外做timeout之后的类成员函数做回调函数数

前端面试题——深入探究 setTimeout - 简书
前端面试题——深入探究 setTimeout
我们经常会碰到一些需要定时执行的需求,比如轮播图、延迟消失等,这时候我们就会用到 setTimeout 这个方法了,设定一个回调函数和等候执行的时间,就可以实现定时或延时的需求
但是 setTimeout 的功能并不只是这么简单,同时使用它时,需要注意的问题也并不少,下面就来深入探究一下 setTimeout
setTimeout( function|string, number );
setTimeout 方法接收两个参数,第一个参数为回调函数函数或字符串,第二个参数为触发时间(单位:毫秒)
setTimeout( function() {
console.log('console after 1 second');
}, 1000 );
// console after 1 second
上面这段代码将会在 1 秒后在控制台打印出 console after 1 second
setTimeout(
'console.log("console after 2 seconds")',
// console after 2 seconds
当第一个参数为字符串,而不是函数时会怎样呢?setTimeout 方法会将这个字符串解析为一段 js 代码,然后在 2 秒后执行这段代码。如果这个字符串无法被解析为 js 代码,将会报错
setTimeout 的返回值
var timeout = setTimeout(function() {
console.log('this is a timeout')
console.log(timeout, typeof timeout);
// 1, "number"
// this is a timeout
用变量 timeout 接收 setTimeout() 的返回值,然后将 timeout 打印出来,会发现 timeout 的值是 1,类型是number
为什么 setTimeout() 的返回值会是一个数值类型呢?是不是每一个 setTimeout() 的返回值都会是1?
var timeout1 = setTimeout(function() {
var timeout2 = setTimeout(function() {
var timeout3 = setTimeout(function() {
console.log('timeout1---', timeout1);
console.log('timeout2---', timeout2);
console.log('timeout3---', timeout3);
// timeout1--- 1
// timeout2--- 2
// timeout3--- 3
从上面的代码中能够发现,每一个 setTimeout()的返回值都不同,返回值并不都是1,而是都对应着唯一的一个值
这个值其实就是对应的setTimtout()的 ID,随着当前页面定时器的不断增多,当需要对某一个定时器做操作时,通过 ID 就能够确定到该定时器
如何结束/阻止一个 setTimeout 的执行
实际项目中,添加一个定时器以后,在其回调函数还未执行之前,满足某些条件时可能需要阻止该回调的执行,也就是取消一个定时器,那这时候该怎么做呢?javascript 已经为我们提供了现成的方法:
clearTimeout( timeout );
上面这个方法就可以阻止一个定时器的执行,它接收一个参数,这个参数就是需要取消的定时器的 ID,也就是该定时器的返回值
var timeout = setTimeout(function() {
alert('this is a timeout')
clearTimeout( timeout );
上面代码中的定时器timeout在一秒后并不会执行,因为已经通过clearTimeout( timeout )取消了它的执行
因为timeout的值是1,所以clearTimeout( 1 )也能够取消这个定时器的执行
实现异步编程
在之前的文章中已经讲过异步编程的概念,我们使用异步编程很重要的一个目的就是为了不因为耗时任务而阻塞其他 js 代码的执行
我们知道alert会阻塞 js 代码的执行,这是因为 js 是单线程的,弹出框出现后如果不对其进行操作就无法执行后面的代码(类似的confirm也是)
alert('this is an alert box');
var test = 'this is a text string';
console.log(test);
上面的代码在弹出框出现后如果不点击确定,将永远不会执行后面的代码
setTimeout(function() {
alert('this is an alert box');
var test = 'this is a text string';
console.log(test);
// this is a text string
上面的代码将alert放在了一个延时 1 秒的定时器中,这样就会先打印出test,过一秒后再显示弹出框
或许你会说,本身alert就延时了 1 秒执行,当然不会阻塞其他的代码执行。那么你可以试着将延时1000改为0,这就表示弹出框应该是没有延时立即执行,但是你会发现实际上还是先打印出test,再执行了alert。为什么会这样呢?我们下面再说
在实际项目中,我们可以利用setTimeout的异步特性,解决一些问题,比如某个对象还未实例化,为了保证该对象在使用到时能够确保已经被实例化,就可以通过setTimeout来实现
setTimeout 回调函数的执行时机
现在我们来说说为什么延时设为 0 ,回调函数却没有立即执行的问题
我们知道浏览器是基于事件循环的,其中会有多个队列,页面的渲染是一个队列,js 代码的执行也是一个队列
js 代码执行时会创建一系列的任务,而这些任务秉承着先进先出的原则被加入到队列中。但是setTimeout是特殊的,当执行到setTimeout时,js会将其拿出来放到一个单独的特殊队列中,这个队列中的任务在 js 队列还有未执行完的任务时,永远不会被执行
举个不恰当的栗子,小明想玩游戏,但是作业还没做完,由于小明是单线程的,虽然现在很想玩游戏,但是他还是给自己设定了条件:作业不做完不能玩游戏,一做完立刻玩游戏(延时为0),于是玩游戏这个任务就被小明归置到了一个特殊的任务队列里面,在作业队列所以任务完成之前不执行特殊队列里面玩游戏的任务,作业完成小明闲下来后立刻开始玩游戏(似乎有点啰嗦,但这不重要:)
所以只有浏览器的 js 引擎闲下来以后,才会执行所有 setTimeout,即使延时为 0
var flag =
setTimeout(function() {
while(flag) {}
alert('this is an alert box');
问:上面的代码什么时候会显示弹出框?
答:永远都不会
上面的代码中,while是一个耗时函数,虽然setTimeout只延时了一秒执行,但是由于主队列中的while会永远的执行下去,所以setTimeout所在的队列永远不会被执行,代码会永远阻塞在while循环这边
当然,上面的这种无限循环在项目中不可能出现,而代码执行速度极快,只要不出现十分耗时的代码,定时器几乎还是能够按照我们的意愿在指定时间执行回调函数
通过 setTimeout 优化用户体验
既然setTimeout必须等到主队列中的任务执行完以后才会执行,那我们在碰到一些十分耗时的代码时,是不是可以通过它来放在页面的阻塞呢?
当然是可以的,将耗时代码写进setTimeout的回调,时间设置为 0,这样只要 js 引擎空闲下来就回去执行这些耗时代码,就不会阻塞页面,给用户造成卡顿的体验,提升用户体验
不易察觉的危险——内存泄漏
什么是内存泄漏?
一块内存在分配使用完毕以后,既不会被再次使用,又没有被及时回收,直到程序执行完毕都始终占据着这块内存
setTimeout 什么情况会导致内存泄漏?
setTimeout的第一个参数可以是函数,也可以是字符串。当传入字符串时,就会有内存泄漏产生。先看下面两个例子
setTimeout(function test1() {
var a = 1;
console.log(a);
function test2() {
var b = 1;
console.log(b);
setTimeout(test2.toString(), 0)
执行代码后,打开控制台,分别输入函数名test1和test2
// Uncaught ReferenceError: test1 is not defined
// ... (打印出 test2 的函数体)
会发现,当第一个参数为函数时,回调函数执行完毕后,test1函数被销毁,其所使用内存也被释放;当第一个参数为字符串时,test2却始终存在,它没有被销毁,始终占据着内存,也就造成了内存泄漏
所以让我们需要使用 setTimeout时,一定要注意,第一个参数必须传入一个函数
不要在项目中频繁大量的使用
上面说了那么多关于 setTimeout的内容,但最后还是要说一下的时,能不使用就不要使用setTimeout,异步编程实现的方式有很多,Promise 和 Generator 都能够实现,而频繁的使用 setTimeout会导致程序的生命周期混乱,虽然会带来一时的便利,但它也会带来很多意想不到的麻烦
所以,除非不得不使用定时器,否则就不要使用
文章中如有任何错误,欢迎指出,虚心受教感激不尽
扫一扫关注微信公众号
如果你喜欢这里的文章,就快不要吝啬你的喜欢啦!
【前端周记】微信公众号【weekly-front-end】已正式开始运营,小伙伴们快搜索公众号关注,或者进入文章内部扫描二维码进行关注吧!
你的鼓励是我前进的动力哦!这样才能写出更多更好的文章啊!
【拖延记录】
嗯,不得不说这个月的事真的非常多。明早要去考科目二(悲催的今年才开始学),整个一周都是在公司和驾校度过的,完全没有时间写文章。
所以很对不起大家的是,这周的文章又要延期了,但是保证明天(周一)上午考完科目二,晚上不管再晚都会发布这周的文章。
同时也保证下周的文章一定一定一定不会再延期了!感谢各位的支持和体谅!!!送你们一个么么哒?
然后也希望自己能够顺利通过科目二,如果能够一次通过,要么下周或者下下周,更新两篇文章来还愿!!!各路大神保佑?
周五开始感冒,周六就发烧了,一直到现在都没全好,整个人昏昏沉沉的完全没有精力做正事。
半个月内的第二次发烧,也是这个月内的第二次拖更,实在是罪过。。。
保证最迟周二补上这周的文章。现在我得去好好休养了。。。
嗯,这周很久没见的好基友来了,于是到处浪啊浪啊浪啊浪,于是很悲催的这周的文章没时间写了,但是保证最晚下周二一定更新!小伙伴们请原谅我又一次不得已的拖更!么么哒
这个周末真的是太忙了,完全没有时间来写本周的周记,但是明天一定会补上
希望各位小伙伴能够谅解偶尔的延迟。
不管怎么说,还是很抱歉没能及时更新。
送你们一个么么哒javascript的setTimeout()用法总结,js的setTimeout()方法
113860次浏览
js的setTimeout方法用处比较多,通常用在页面刷新了、延迟执行了等等。但是很多javascript新手对setTimeout的用法还是不是很了解。虽然我学习和应用javascript已经两年多了,但是对setTimeout方法,有时候也要查阅资料。今天对js的setTimeout方法做一个系统地总结。
setInterval与setTimeout的区别
说道setTimeout,很容易就会想到setInterval,因为这两个用法差不多,但是又有区别,今天一起总结了吧!
setTimeout
定义和用法: setTimeout()方法用于在指定的毫秒数后调用函数或计算表达式。  
语法: setTimeout(code,millisec)  
参数: code (必需):要调用的函数后要执行的 JavaScript 代码串。millisec(必需):在执行代码前需等待的毫秒数。
提示: setTimeout() 只执行 code 一次。如果要多次调用,请使用 setInterval() 或者让 code 自身再次调用 setTimeout()。
setInterval
setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。
setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。
setInterval(code,millisec[,&lang&])
code 必需。要调用的函数或要执行的代码串。millisec
必须。周期性执行或调用 code 之间的时间间隔,以毫秒计。
一个可以传递给 Window.clearInterval() 从而取消对 code 的周期性执行的值。
通过上面可以看出,setTimeout和setinterval的最主要区别是:
setTimeout只运行一次,也就是说设定的时间到后就触发运行指定代码,运行完后即结束。如果运行的代码中再次运行同样的setTimeout命令,则可循环运行。(即 要循环运行,需函数自身再次调用 setTimeout())
而 setinterval是循环运行的,即每到设定时间间隔就触发指定代码。这是真正的定时器。
setinterval使用简单,而setTimeout则比较灵活,可以随时退出循环,而且可以设置为按不固定的时间间隔来运行,比如第一次1秒,第二次2秒,第三次3秒。
我个人而言,更喜欢用setTimeout多一些!
setTimeout的用法
让我们一起来运行一个案例,首先打开记事本,将下面代码贴入,运行一下效果!
&!DOCTYPE html&
&meta http-equiv=&Content-Type& content=&text/ charset=UTF-8&&
&h1& &font color=blue& haorooms博客示范网页 &/font& &/h1&
&p& 请等三秒!&/p&
setTimeout(&alert('对不起, haorooms博客要你等候多时')&, 3000 )
页面会在停留三秒之后弹出对画框!这个案例应用了setTimeout最基本的语法,setTimeout不会自动重复执行!
setTimeout也可以执行function,还可以不断重复执行!我们再来一起做一个案例:
&!DOCTYPE html&
&meta http-equiv=&Content-Type& content=&text/ charset=UTF-8&&
function countSecond()
  document.haorooms.haoroomsinput.value=x
  setTimeout(&countSecond()&, 1000)
&form name=&haorooms&&
&input type=&text& name=&haoroomsinput&value=&0& size=4 &
countSecond()
&/body& &/html&
你可以看到input文本框中的数字在一秒一秒的递增!所以,setTimeout也可以制作网页中的时间跳动!
没有案例,学习起来不会很快,我们再来一起做一个例子,计算你在haorooms某个页面的停留时间:
&!DOCTYPE html&
&meta http-equiv=&Content-Type& content=&text/ charset=UTF-8&&
function countMin()
  document.displayMin.displayBox.value=y
  setTimeout(&countMin()&,60000)
function countSec()
{ x = x + 1
  z =x % 60
  document.displaySec.displayBox.value=z
  setTimeout(&countSec()&, 1000)
&/script& &/head&
&table& &tr valign=top& &td& 你在haorooms博客中的停留时间是: &/td&
&form name=displayMin&
&input type=text name=displayBox value=0 size=4 &
&td& 分 &/td&
&form name=displaySec& &/td&
&td& &input type=text name=displayBox value=0 size=4 &
&td& 秒。&/td& &/tr&
countMin()
countSec()
怎么样,通过上面的例子,对setTimeout()的用法,相信你都了解了吧!
clearTimeout( )
我们再来一起看一下 clearTimeout( ),
clearTimout( ) 有以下语法 :  
clearTimeout(timeoutID)
要使用 clearTimeout( ), 我们设定 setTimeout( ) 时 , 要给予这 setTimout( ) 一个名称 , 这名称就是 timeoutID , 我们叫停时 , 就是用这 timeoutID 来叫停 , 这是一个自定义名称 , 但很多人就以 timeoutID 为名。
在下面的例子 , 设定两个 timeoutID, 分别命名为 meter1 及 meter2, 如下 :
meter1 = setTimeout(“count1( )”, 1000)
meter2 = setTimeout(“count2( )”, 1000)
使用这 meter1 及 meter2 这些 timeoutID 名称 , 在设定 clearTimeout( ) 时 , 就可指定对哪一个 setTimeout( ) 有效 , 不会扰及另一个 setTimeout( ) 的操作。
下面请看 clearTimeout()的案例
&!DOCTYPE html&
&meta http-equiv=&Content-Type& content=&text/ charset=UTF-8&&
function count1()
{ x = x + 1
  document.display1.box1.value = x
  meter1=setTimeout(&count1()&, 1000)
function count2()
{ y = y + 1
  document.display2.box2.value = y
  meter2=setTimeout(&count2()&, 1000)
&/script& &/head&
&form name=&display1&&
&input type=&text& name=&box1& value=&0& size=4 &
&input type=button value=&停止计时& onClick=&clearTimeout(meter1) & &
&input type=button value=&继续计时& onClick=&count1() & &
&form name=&display2&&
&input type=&text& name=&box2& value=&0& size=4 &
&input type=button value=&停止计时& onClick=&clearTimeout(meter2) & &
&input type=button value=&继续计时& onClick=&count2() & &
通过上面的讲解,不知道您对setTimeout了解了没有,下次使用setTimeout会不会很熟练?会不会再把setTimeout和setInterval搞混了?要是您有什么不了解的地方,可以相互交流,共同提高,谢谢!
相关文章:
关键词搜索使用计时函数
函数描述lark.getTimer()返回自 Lark 框架初始化以来经过的毫秒数lark.startTick()在设备刷新屏幕前运行函数,每秒大约触发60次lark.stopTick()取消指定的 lark.startTick() 调用。setInterval()以指定的间隔(以毫秒为单位)运行函数。clearInterval()取消指定的 setInterval() 调用。setTimeout()在指定的延迟(以毫秒为单位)后运行指定的函数。clearTimeout()取消指定的 setTimeout() 调用。获取准确时间戳使用lark.getTimer()可以获得一个当前绝对时间戳,表示从Lark框架初始化以来经过的毫秒数,通常我们使用两个时间戳的差值来计算代码的执行时间。下列代码展示了如何计算一段循环代码的执行时间://&记录起始的时间戳
var&time&=&lark.getTimer();
for(var&i=0;i&1000000;i++){
&&&&if(isNaN(5)){
lark.log((lark.getTimer()-time)+&ms&);以上代码最终会在控制台输出具体执行时间长度,若输出为:16ms,表示指定的for循环代码块共执行了16毫秒。另外,通常 lark.getTimer() 还用于解决计时器回调时间间隔不准确的问题。要注意:任何计时器的回调时间都不是绝对准确的,因为有可能受到逻辑代码执行的影响而延后,尤其是当您将时间间隔设置的非常短时。为了避免时间不准确,通常可以在每次回调触发时,使用 lark.getTimer() 来记录下当前准确的时间戳,从而根据两次时间戳计算出准确的时间间隔。循环多次运行函数lark.startTick() 与 setInterval() 都能够以一定时间间隔循环触发指定的函数,区别是前者的时间间隔无法指定,它通常以每秒60次的固定频率运行指定函数,且运行函数的时刻是在设备即将刷新屏幕前。此函数通常用于编写缓动动画,能够获得更加流畅的缓动效果。而 setInterval() 函数能够以您指定的时间间隔去运行回调函数,理论上您可以设置时间间隔为16.6ms也能达到lark.startTick()相同的回调频率,但是setInterval()并不能保证回调时刻正好是在设备刷新屏幕前,因此 setInterval() 函数更合适执行纯逻辑代码。这两个函数一旦被调用,回调函数将会不间断持续运行,您可以分别使用lark.stopTick()和clearInterval() 函数来停止回调触发。下列代码演示了调用 setInterval() 函数来设置每隔1秒执行一次回调函数,并在5秒后停止回调:var&intervalID&=&setInterval(onTick,1000);
var&count&=&0;
function&onTick(){
&&&&count++;
&&&&if(count&5){
&&&&&&&&//&停止触发回调
&&&&&&&&clearInterval(intervalID);
&&&&&&&&lark.log(&每隔1秒执行&);
}延迟一次运行函数setTimeout()函数能够根据您指定的时间长度延迟执行回调函数。与setInterval()有区别的是它只回调一次。以下代码演示了如何延迟执行一个函数:setTimeout(delayCall,5000);
function&delayCall():void{
&&&&lark.log(&延迟5秒执行&);
}执行以上代码,您将会在5秒后才看到控制台输出:延迟5秒执行
注:本文转载自Dom,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除。
我可能需要关注的开源项目? >
我可以选择哪些技术支持? >
我可以选择哪些培训方式?>
过去的内容?>
(已满) (已满) (已满) (已满) (未满)
Copyright (C) . 京ICP备号 京公网安备02setTimeout的执行顺序,小记js中的异步原理
故事起因于一段简短的代码,我以为我懂了,结果查了一天,框框中的代码为什么永远不会执行,自己做了测试,发现如果setTimeout里的code,如果是一个函数的话即使延迟时间是0,也会在函数后面执行,但是如果是一个语句,如('aa');则会立即执行(主意哦我说的是一个语句,不是字符串)。
根据高程和权威指南上面的说法,setTimeout(code,delay),delay是数字,单位是毫秒,code可以是函数或者是字符串,但是不推荐字符串,会影响性能;(权威指南)如果以0毫秒的超时时间来调用setTimeout(),那么指定的函数不会立即执行,相反会把它放到队列中去,等到前面处于等待状态的事件处理程序全部执行完成后,再“立即”调用它。(setTimeout和setInterval经常有不守时的时候)。
如果code为字符串,相当于执行eval_r(),可以看做是function(){eval_r(字符串)};表现与code为函数时是一致的,只有在执行队列为空的时候才执行(已达到延迟时间);
js中的异步原理
要先说明,js引擎是单线程滴,但是浏览器是多线程滴。基于这一点才能实现的异步,浏览器中只有一个线程用于js引擎处理事件,像setTimeout()中要计算延迟时间,浏览器的事件触发,http请求等等这些是浏览器的其他线程做的,不是js的那个线程,当这些线程完成之后会给js引擎一个通知,这些任务(回调函数)在js的任务队列中进行排队,一个一个被引擎处理。
再说setTimeout和setInterval经常不守时
setTimeout的延时为0时并不会立即触发,一个是浏览器自身就有一个几毫秒更新频率,另一个就是异步队列的问题,setTimeout中的回调函数会加入等待队列,在等待延迟触发的过程中,有新的同步脚本需要执行的话,新的同步脚本不会排在setTimeout的回调函数之后,而是立即执行。
setInterval不会考虑当前在执行什么,而是把所有的阻塞函数都排到队列尾部,当一个很长的代码块在执行时,可能把所有的setInterval回调函数都排在队列的后面,代码执行完成之后便是一大串的setInterval回调函数等待执行,并且这些函数之间没有间隔,直到全部完成。更加详细的解释可以参看
文章组织凌乱,加上js功力尚浅,大家也可以直接跳过参看这几篇文章,都是我绝得看的比较明白的几篇
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。js中setTimeout() clearTimeout()_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
js中setTimeout() clearTimeout()
&&js中setTimeout() clearTimeout()
你可能喜欢

我要回帖

更多关于 js 回调函数 的文章

 

随机推荐