setTimeout你知多少
假期这么快就结束了,其实对我来说没什么影响,因为我一周才两节课,对于课多的同学来说,我天天在休假,不要羡慕哟~ 但休假并不代表闲着,还是得苦逼的编代码,唉。。一入程序深似海。。
不管学得多少,还是总结一些,还是一些小问题。当然也是很重要的,好! 废话少说该入正题了。
上次提到异步,当时说,不知道是啥就去查汉语字典,但后来发现查了字典还是不会。回顾一下
js哪些操作是异步的???setTimeout、setInterval、ajax、各种事件处理,才疏学浅,我就知道这些,谁还知道有哪些,劳烦告诉我,学习学习。
for(var i=0; i<5; i++){
setTimeout(function(){
console.log(i);
},100);
} //答案是: 5 5 5 5
for(var i=0; i<5; i++){
(function(j){
setTimeout(function(){
console.log(j);
},100);
})(i);
}; 答案是 0 1 2 3 4
为什么是这个答案,重申一遍:作用域的关系。具体解释:作用域与执行环境无关,由定义时决定并一步一步往上查找。上述两个例子 执行匿名函数时执行的是:
function(){
console.log(i);
} 而i等于多少? 我们从定义处查找 setTimeout中没有i 在往上一层就到了全局中,此时i已经等于5 所以答案是全是5
function(){
console.log(j);
} 而j等于多少? 我们还是从定义处查找 setTimeout中没有j 在往上一层就到了上一个形参为j的匿名函数,此时j是形参,在定义setTimeout中的函数时,j的形参依次被传入实参i,依次为0,1,2,3,4 所以答案是全是0,1,2,3,4
换汤不换药,找个例子实验一下:
[1,2,3,4,5].forEach(function(elem){
setTimeout(function(){console.log(elem)}, 200);
}) 答案是多少?? 5,5,5,5?? 1,1,1,1?? 1,2,3,4,5还是??? 答案是1,2,3,4,5 如果错了的话,再把前面的例子,文字看看。
继续,再来一道:
for(var i=0; i<5; i++){
(function(j){
setTimeout(function(){
console.log(j);
}, Math.random()*1000);
})(i);
} //这个答案是什么呢?? 是0,1,2,3,4还是什么??? 好好想想。
根据前面的分析,先找定义处 依次往上查找,到function(j)这个函数时,已经把实参i传进来了,所以答案是0,1,2,3,4 yes or no?? 答案是错误的。为什么?
实参i确实把值传进来了,该段代码就等价于
setTimeout(function(){
console.log(0);
}, Math.random()*1000); setTimeout(function(){
console.log(1);
}, Math.random()*1000); setTimeout(function(){
console.log(2);
}, Math.random()*1000); setTimeout(function(){
console.log(3);
}, Math.random()*1000); setTimeout(function(){
console.log(4);
}, Math.random()*1000); 此时只看这段代码 答案是多少??? 大家肯定会说是乱序的,跟 (Math.random()*1000) 值有关,yes 你答对了。 所以上面那个答案是乱序的0,1,2,3,4
那么,下面那个代码呢?
setTimeout(function(){
console.log(15);
},100);
setTimeout(function(){
console.log(5);
},200);
很多人肯定会说,这还用说吗? 不用想都知道是15, 5。对,但是就这段代码而言,这个15,5 从等待到执行(此处执行时间忽略不计)一共是花了300ms还是200ms呢? 答案是200ms,为什么?刚刚开头就说过,setTimeout()函数是异步的,异步有个的特点就是并发性,在同时定义这两个函数时,他们同时在等待,放入到消息队列中,所以100ms后第一个函数放入时,第二个函数已经等了100ms,所以两个函数一共等了200ms。 总之一句话:异步具有并发性,与顺序无关(时间相同或者相近的情况下有关),与时间的快慢有关,请记住它。
这里还要提的是:关于定时器中的时间,指的是何时将定时器的代码添加到队列中,而不是何时实际执行代码,只能表示它会尽快执行。
如 :
document.onclick = function(){
setTimeout(function(){
console.log(34);
},250);
}; //如果onclick事件处理程序执行了300ms 那么定时器代码至少要在定时器设置后的300ms才会被执行,也就是34至少要在300ms后输出。
大家马上就想到,如果是这样的话,setInterval()就会出现一种情况:在代码再次被添加到队列之前没完成执行,导致定时器代码连续运行好几次,没有停顿。幸好,js引擎够聪明,能避免这个问题,如何避免?当使用setInterval()时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中,这样确保了定时器代码加入到队列中的最小时间间隔为指定间隔,注意是添加到队列中的最小时间间隔而不是执行。但是。。这个规则有两个问题:1.某些间隔会被跳过,2.多个定时器的代码执行之间的间隔可能会比预期的少。举个例子:
某个onclick事件处理程序使用setInterval()设置了一个200ms间隔的重复定时器,如果事件程序花了300ms多一点的时间完成,定时器也花差不多的时间,就会出现上述两个问题。
如图: 此图来自《js高级程序设计》这本书强烈推荐阅读。。。
我们分析一下:在5ms时创建了间隔为200ms的定时器,第一个定时器在205ms后被添加到队列中,但直到onclik执行完才执行,执行时,在405ms处第二个定时器又被添加到队列中,在605ms第三个定时器要添加到队列中,但此时第二个定时器还没被执行,所以第三个不会被添加,同时在第一个定时器执行完之后第二个立即执行,所以第一个定时器和第二个定时器执行的间隔小于200ms,其实此处就是从第一个执行结束到第二个开始执行没有间隔。
有人可能想到这样的话js引擎并没有解决定时器代码连续运行问题,确实,但其实js引擎这种做法(在仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中),减少了连续的次数,不至于堆积太多。
为了避免这2个缺点,可以使用如下模式使用链式setTimeout()调用。
setTimeout(function(){
//处理中
setTimeout(arguments.callee,interval); //arguments.callee 获取对当前函数执行的引用。 //此处把需要处理的代码写在前面 有一个好处是 :下一个定时器一定是在前一个将要结束(此处可以之直接视为结束)才定义
}, interval);
每次函数执行时创建一个新的定时器,这样的好处:在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔,而且,它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。详细请看《js高级程序设计》这本书。
关于setTimeout()函数还有一点就是:
大家都知道DOM比非DOM交互要更多的内存和CPU时间,如果连续进行过多的DOM相关操作可能会导致浏览器挂起甚至崩溃。如resize事件,为了绕开这个问题我们可以使用setTimeout();
模式如下:
var processor = {
timeoutId: null,
performProcessing: function(){
//实际执行代码
},
process: function(){
clearTimeout(this.timeoutId);
var that = this; //保存this,因为setTimeout()中用到的函数环境总是window
this.timeoutId = setTimeout(function(){ //timeoutId用来保存本次setTimeout的id以便下一次调用时清除
that.performProcessing();
}, 100);
}
}; processor.process();
时间间隔设为100ms,表示最后一次调用process()之后至少100ms后才会被调用performProcessing(),如果100ms之内调用了process()共20次,performProcessing()仍只会被调用一次。因为,在100ms之内定时器都没开始执行,调用process()只会清除前一次的,最后只剩下最后一次setTimeout()。也就是说performProcessing()仍只会被调用一次。
这个过程叫做函数节流,基本思想是:某个代码不可以在没有间断的情况连续重复执行。今天先暂且消化这些。
哪不对,或者要补充,推荐的强烈欢迎。。。
setTimeout你知多少的更多相关文章
- 微信小程序开发日记——高仿知乎日报(上)
本人对知乎日报是情有独钟,看我的博客和github就知道了,写了几个不同技术类型的知乎日报APP 要做微信小程序首先要对html,css,js有一定的基础,还有对微信小程序的API也要非常熟悉 我将该 ...
- 微信小程序之知乎日报
上一次的<微信小程序之小豆瓣图书>制作了一个图书的查询功能,只是简单地应用到了网络请求,其他大多数小程序应有的知识.而本次的示例是知乎日报,功能点比较多,页面也比上次复杂了许多.在我编写这 ...
- 你真的了解setTimeout和setInterval吗?
博客园的代码排版真难用,编辑时候是好的,一保存就是乱了——本文也同时发表在我另一独立博客上 你真的了解setTimeout和setInterval吗?,可以移步至这里吧 setTimeout和setI ...
- 关于setTimeout的妙用前端函数节流
最近在某团队忙于一个项目,有这么一个页面,采用传统模式开发(吐槽它为什么不用React),它的DOM操作比较多,然后性能是比较差的,尤其当你缩放窗口时,可怕的事情发生了,出现了卡顿,甚至浏览器瘫痪.为 ...
- 关于JavaScript中的setTimeout()链式调用和setInterval()探索
http://www.cnblogs.com/Wenwang/archive/2012/01/06/2314283.html http://www.cnblogs.com/yangjunhua/arc ...
- js setTimeout深度递归后完成回调
setTimout原型: iTimerID = window.setTimeout(vCode, iMilliSeconds [, sLanguage]) setTimeout有两种形式 se ...
- js定时器window.setTimeout和setInterval
window.setTimeout(function(){ document.getElementById("editorindex&q ...
- setTimeout小总结
▓▓▓▓▓▓ 大致介绍 今天看了一篇文章,觉得写得不错,所以学习了一下,这篇博客是我自己的理解和总结 原文:你应该知道的 setTimeout 秘密 主要内容: 1.setTimeout原理 2.se ...
- 一篇知乎的故事 - javascript技术贴
前言 就像文章题目所示,本文的发表源于知乎的一篇文章.文章链接如下:如果你想靠前端技术还房贷,你不能连这个都不会.这篇文章是群里水群时别人发的,像我这样的菜鸟角色才不会逛知乎~~~.这篇文章主要是讲了 ...
随机推荐
- JNDI(Java Naming and Directory Interface,Java命名和目录接口)
JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访 ...
- hexdump related.
hexdump format strings Tue 13 December 2005 In tips. Ian Wienand More from the "things you'd le ...
- js写一个插件
//;分号开头,用于防止代码压缩合并时与其它代码混在一起造成语法错误 //而事实证明,uglify压缩工具会将无意义的前置分号去掉,我只是习惯了这么写 //(function(){})();立即执行函 ...
- [实战]MVC5+EF6+MySql企业网盘实战(18)——文件上传,下载,修改
写在前面 经过一段时间的秀秀改改,终于把文件上传下载,修改文件夹文件名称的功能实现了. 系列文章 [EF]vs15+ef6+mysql code first方式 [实战]MVC5+EF6+MySql企 ...
- Cookie机制和Session机制
1. cookie 1. Cookie 是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式.Cookie 是由 Web服务器保存在用户浏览器(客户端)上的小文本文件(内容通常经过加密) ...
- 【SQL SERVER】触发器(一)
下面是个人对触发器知识的整理,触发器其实很简单,但想要编写发杂的触发器操作还是需要一定的SQL语句编写,触发器主要用于SQL SERVER约束.默认值和规则的完整性检查,还可以实现由主键和外键不能保证 ...
- 小学生都能理解的原生js——call
关于 js 作用域和执行上下文就不过多介绍了,本人也是在网上搜集了各种教程才逐渐理解,以下简单理解并说下call 的作用 首先简单理解下执行上下文有关概念,this 的指向就代表当前执行环境的上下文 ...
- sublimetext3-实用快捷键整理
实用快捷键 Ctrl+Shift+P:打开命令面板Ctrl+P:搜索项目中的文件Ctrl+G:跳转到第几行Ctrl+W:关闭当前打开文件Ctrl+Shift+W:关闭所有打开文件Ctrl+Shift+ ...
- Python数据类型-集合(set)
1.创建集合 集合的创建不同于前两种数据结构. 集合通过set(iterable)方法创建,参数iterable为可迭代对象. 示例代码: s1 = set('好好学习天天想上') # 将字符串分解为 ...
- react篇章-React 组件-向组件传递参数
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title&g ...