深入理解JavaScript定时器
对于浏览器内部,大部分操作都是异步的生成事件并添加到JavaScript引擎线程
的队列中,然后由JavaScript引擎线程
进行调度执行。因此浏览器的很多事件都是和JavaScript
相结合的,但是也有一些内部的限制。
首先我们非常确定JavaScript
是单线程的,对于浏览器来说,一个窗体中只有一个JavaScript引擎线程
。而其他的行为,如:渲染、下载等是由单独的线程进行管理的,且具有不同的优先级。
异步事件
前面提到大多数事件都是异步的,触发的时候就将回调函数添加到事件队列。浏览器提供了一个内部的回路,也就是之前所谈到的Event Loop
,由它来负责检查队列和处理事件、执行函数等。详细可参考我的前一篇博文。而setTimeout
和setInterval
也是将其需要执行的函数添加到事件队列。
事实上,大多数交互和活动都得通过事件循环。
事件重叠
一些情况下,会有多个事件在同一时间附加到事件队列里。
比如,click
事件就会产生两个额外的事件:mousedown
和mouseup
。其中,mouseup
和click
事件会同时被添加到事件队列;而mousedown
事件则很有可能会和另外一个事件重叠:focus
。
setTimeout(func, 0)奇巧淫技
再一次解释关于0ms
的误解:如果当前时钟周期内执行队列空闲,则立即执行该定时器,将回调函数加入到事件队列;然后等待下一个时钟周期,再执行该回调函数。不妨来看看下面的测试。
这段代码在我的浏览器中执行结果如下:
在我本地的Nodejs
环境中执行结果如下:
上面的这个测试只是想说明setTimeout(func, 0)
定时任务的回调函数执行时间是有延迟的,而并不是所谓的立即执行。
因此,我们可以利用setTimeout(func, 0)
来解决事件重叠所产生的负面效果,修正执行顺序。
奇巧淫技之一:模拟浏览器的事件捕获
众所周知,浏览器的DOM事件都是采用冒泡的方式,只有个别浏览器是支持事件捕获的。而在实际的开发过程中可能存在需要事件捕获的需求,要求子元素的事件在父元素触发之后才能触发。为了兼容各个浏览器,我们不能使用事件捕获,而setTimeout(func, 0)
在这个时候就很乐意帮忙了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<input type="button" value="click" id="cbtn"> <div id="result"></div> <script type="text/javascript">var cbtn = document.getElementById('cbtn'), result = document.getElementById('result');cbtn.onclick = function(e) {setTimeout(function() {result.innerHTML += 'input click, ';}, 0);};document.body.onclick = function(e) {result.innerHTML += 'body click -> ';}; </script> |
点击查看运行效果:
奇巧淫技之二:让浏览器更好的工作
大多数情况下,我们可以在浏览器的默认行为之前对事件进行处理,但是有时我们按照常规的思路去做的时候,往往事与愿违。比如下面的例子。
1 2 3 4 5 6 7 |
<input type="text" id="wordInput"> <script type="text/javascript">var wordInput = document.getElementById('wordInput');wordInput.onkeypress = function(e) {this.value = this.value.toUpperCase();}; </script> |
看似一个很简单的需求:每输入一个字符,就将其转换为大写。但是上面的代码完全没有按照指示去做,不信你试试看:
如果没有下一次输入,文本框中的小写字母永远都不会转换为大写。Why? 因为浏览器在keypress
事件处理的时候,还没有将我们输入的值添加到文本框。于是乎换一个事件来handle然后再处理吧,既然键按下的时候还木有值,那就等键弹起来之后再处理。
1 2 3 4 5 6 7 |
<input type="text" id="wordInput"> <script type="text/javascript">var wordInput = document.getElementById('wordInput');wordInput.onkeyup = function(e) {this.value = this.value.toUpperCase();}; </script> |
运行试试吧。
大概似乎是可行了,可是仔细观察就看出问题了。keyup
事件触发时,文本框已经具备完整的值了,但先是一个小写的值,键完全释放之后转变为大写。这不科学…这太丑陋...
是时候关门放出setTimeout(func, 0)
了。。。
1 2 3 4 5 6 7 8 9 10 |
<input type="text" id="wordInput"> <script type="text/javascript">var wordInput = document.getElementById('wordInput');wordInput.onkeypress = function(e) {var self = this;setTimeout(function() {self.value = self.value.toUpperCase();}, 0);}; </script> |
已经完美了。keypress
事件触发时,将转换大写的操作添加到事件队列,紧接着浏览器添加我们输入的值,然后近乎0延迟的执行我们的转换大写操作函数。
上面两个小案例只是冰山一角,so...合理利用setTimeout(func, 0)
,明天更美好!
深入理解JavaScript定时器相关推荐
- js等待当前线程内ajax完成,理解javascript定时器中的单线程
一.JavaScript 引擎是单线程的 可以从下面的代码中看到,第一个用setTimeout中的代码是死循环,由于是单线程,下面的两个定时器就没机会执行了. setTimeout( function ...
- 深入理解JavaScript定时机制
容易欺骗别人感情的JavaScript定时器 本文地址: http://www.laruence.com/2009/09/23/1089.html 转载文章 JavaScript的setTimeout ...
- JavaScript可否多线程? 深入理解JavaScript定时机制
JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout( ...
- JavaScript定时器的工作原理(翻译)
JavaScript定时器的工作原理(翻译) 标签(空格分隔): JavaScript定时器 最近在看ajax原理的时候,看到了一篇国外的文章,讲解了JavaScript定时器的工作原理,帮助我很好的 ...
- JavaScript定时器原理及高级使用
JavaScript里面内置了两个定时器,一个是setTimeout()一个是setInterval().下面将由浅入深来理解一下定时器的工作原理. 使用方式: setTimeout() setTim ...
- 深入理解javascript函数系列第二篇——函数参数
前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...
- js 对象深拷贝_这一次,彻底理解JavaScript深拷贝
导语 这一次,通过本文彻底理解JavaScript深拷贝! 阅读本文前可以先思考三个问题: JS世界里,数据是如何存储的? 深拷贝和浅拷贝的区别是什么? 如何写出一个真正合格的深拷贝? 本文会一步步解 ...
- 深入理解JavaScript类数组
起因 写这篇博客的起因,是我在知乎上回答一个问题时,说自己在学前端时把<JavaScript高级程序设计>看了好几遍. 于是在评论区中,出现了如下的对话: 天啦噜,这话说的,宝宝感觉到的, ...
- 深入理解javascript作用域系列第四篇——块作用域
前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...
最新文章
- php-fpm慢执行日志
- 如何实现软件的国际化
- sklearn输出模型参数_如何使用sklearn优雅地进行数据挖掘?
- kompozer+mysql_KompoZer for mac下载_KompoZer for mac版V0.8b3下载(暂未上线)_预约_飞翔下载...
- 分布式文件系统研究-fastDFS安装及配置文件说明
- c++排序算法ppt_C/C++学习教程:C语言排序算法—插入排序算法
- 何小鹏谈财务自由:痛苦彷徨,7块钱的快餐只能偷偷吃
- linux vi设置技巧,vi 技巧
- day04【后台】角色维护
- fwoa中做excel导入时page理解
- SVO深度解析(三)之深度滤波(建图部分)
- 如何建语料库_语料库-如何建设语料?如何建设语料库 爱问知识人
- 产品经理基本功之PRD
- 使用 Kotlin 读取本地视频并使用Vitamio框架编写万能播放器进行播放(二)
- ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新
- 没登录的计算机怎么远程桌面,没有远程登陆工具如何远程电脑 如何用向日葵实现远程登陆?...
- voa android tv,VoAACEncoder
- sl4a库_sl4a之pythonapi中文参考
- 【不生气的智慧】王焕斌--书记
- CentOS6.6下配置KMS自动激活服务器