setTimeout(func, 0)可以使用在很多地方,拆分循环、模拟事件捕获、页面渲染等

一、setTimeout中的delay参数为0,并不是指马上执行

<script type="text/javascript">
function delay1() {
console.log('delay1');
}
function delay2() {
console.log('delay2');
}
function delay3() {
console.log('delay3');
} delay1();
setTimeout(function() {
delay2();
}, 0);
delay3();
</script>

  用firefox的firebug可以查看到,并不是按照delay1,delay2,delay3这样打印的。

  

  由于JavaScript是单线程处理任务的,而setTimeout是异步事件,延时时间为0的时候,JavaScript引擎会把异步事件立刻放到任务队列里,而不是立刻执行,需要等到前面处于等待状态的事件处理程序全部执行完成后再调用它(JavaScript engines only have a single thread, forcing asynchronous events to queue waiting for execution)。JavaScript引擎的运作可以查看前面的文章《Javascript定时器(一)——单线程》

二、拆解循环

循环体中包含太多的操作和循环的次数过多都会导致循环执行时间过长,并直接导致锁死浏览器。如果循环之后没有其他操作,每次循环只处理一个数值,而且不依赖于上一次循环的结果则可以对循环进行拆解。

<script type="text/javascript">
  function delay() {
  for(var i=0; i<100000000; i++) {
//logic
  }
}
delay();
</script>

使用setTimeout拆解循环,用firebug的console.log打印index值。

<script type="text/javascript">
var index = 0;
//使用setTimeout拆解循环
function major() {
if(index > 100000000) {
return;
}
console.log(index);
index++;
setTimeout(function() {
major();
}, 0);
}
major();
</script>

三、模拟事件捕获

浏览器的 DOM 事件都是采用冒泡的方式,在实际的开发过程中可能存在需要事件捕获的需求,要求子元素的事件在父元素触发之后才能触发。

  <p>1、父元素的事件在子元素触发之后触发</p>
<div id="parent">
<a href="javascript:void(0)" id="child">冒泡</a>
<p id="result1"></p>
</div>

  1、一个a按钮

  2、一个p显示结果

  3、一个div作为父级元素

<script type="text/javascript">
//父元素的事件在子元素触发之后触发
function bubbling() {
var child = document.getElementById('child'),
parent = document.getElementById('parent'),
result = document.getElementById('result1');
child.onclick = function() {
result.innerHTML += 'child->';
}; parent.onclick = function() {
result.innerHTML += 'parent->';
};
}
</script>

  1、绑定a按钮的click事件,点击一下打印child

  2、绑定div按钮的click事件,点击一下打印parent

  3、显示结果如下:

  

在a按钮的click事件中加个setTimeout,就能做到子元素的事件在父元素触发之后触发了,这里也是JavaScript引擎在起作用。

    child.onclick = function() {
setTimeout(function() {
result.innerHTML += 'child->';
}, 0);
};

四、页面渲染

浏览器中GUI渲染线程与JavaScript引擎是互斥的,所以当JavaScript执行时,浏览器就不会做任何的页面渲染。

<p>3、页面渲染,阻塞</p>
<a href="javascript:void(0)" id="vary">变换</a>
<div style="width:150px;height:150px;border:1px solid #c6c6c6" id="container"></div>

  1、点击变换按钮,将下面container的宽与高从150减到1。

  2、由于互斥的关系,效果感觉是一下子从150到1了,中间没有那个减小的过程。

<script type="text/javascript">
     //页面渲染
function render() {
var btn = document.getElementById('vary'), container = document.getElementById('container');
btn.onclick = function() {
for (var i = 150; i > 0; i--) {
container.style.height = i + 'px';
container.style.width = i + 'px';
}
};
}
</script>

  1、修改container的height与width会引发回流(reflow),一回流GUI渲染线程线程就会执行。

  2、由于互斥的原因,只有当JavaScript执行完毕后,才会做渲染。

  =》

用setTimeout后,就会出现从150到1的减小过程。

       function vary(i) {
i--;
console.log(i);
container.style.height = i + 'px';
container.style.width = i + 'px';
if(i > 0) {
setTimeout(function() {
vary(i);
}, 0);
}
}
btn.onclick = function() {
var i = 150;
vary(i);
};

Tips:

这里顺便说下重绘(Repaint)与回流(reflow):

重绘(repaints):是一个元素外观的改变所触发的浏览器行为,例如改变vidibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随回流。
回流(reflow):是更明显的一种改变,可以理解为渲染树需要重新计算。

导致 reflow 发生的一些因素:

  1. 调整窗口大小(Resizing the window)
  2. 改变字体(Changing the font)
  3. 增加或者移除样式表(Adding or removing a stylesheet)
  4. 内容变化,比如用户在input框中输入文字(Content changes, such as a user typing text in an input box)
  5. 激活 CSS 伪类,比如 :hover (IE 中为兄弟结点伪类的激活)(Activation of CSS pseudo classes such as :hover (in IE the activation of the pseudo class of a sibling))
  6. 操作 class 属性(Manipulating the class attribute)
  7. 脚本操作 DOM(A script manipulating the DOM)
  8. 计算 offsetWidth 和 offsetHeight 属性(Calculating offsetWidth and offsetHeight)
  9. 设置 style 属性的值 (Setting a property of the style attribute)

demo下载:

http://download.csdn.net/download/loneleaf1/7971185

参考资料:

http://heroicyang.com/2012/09/22/javascript-timer-in-depth/ 深入理解JavaScript定时器

http://heroicyang.com/2012/10/14/javascript-timer-and-event-in-depth/ 深入理解JavaScript定时器(续)

http://my.oschina.net/cupidooo/blog/149379 Web前端:解决浏览器页面回流(reflow)的几种方法

http://www.planabc.net/2009/04/13/reflow/ 影响 reflow 的因素及其优化

http://www.nowamagic.net/librarys/veda/detail/787 优化js脚本设计,防止浏览器假死

Javascript定时器(三)——setTimeout(func, 0)的更多相关文章

  1. Javascript定时器(二)——setTimeout与setInterval

    一.解释说明 1.概述 setTimeout:在指定的延迟时间之后调用一个函数或者执行一个代码片段 setInterval:周期性地调用一个函数(function)或者执行一段代码. 2.语法 set ...

  2. JavaScript下的setTimeout(fn,0)意味着什么?

    近期在研究异步编程的我对于setTimeout之类的东西异常敏感.在SegmentFault上看到了一个问题<关于SetTimeout时间设为0时>:提问者读了一篇文章,原文解释setTi ...

  3. JavaScript定时器:setTimeout()和setInterval()

    1 超时调用setTimeout() 顾名思义,超时调用的意思就是在一段实际之后调用(在执行代码之前要等待多少毫秒) setTimeout()他可以接收两个参数: 1 要执行的代码或函数 2 毫秒(在 ...

  4. javascript 定时器 timer setTimeout setInterval (js for循环如何等待几秒再循环)

    实现一个打点计时器,要求1.从 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一个数字,每次数字增幅为 12.返回的对象中需要包含一个 cance ...

  5. JavaScript定时器及其他

    By Abyssly Jun 20 2014 Updated:Jun 20 2014 平时工作中不可避免地要嵌套网页,对JavaScript的深入了解还是很有必要滴.而JavaScript中一个容易让 ...

  6. 定时器(setTimeout)的秘密

    原文地址:→传送门 写在前面 setTimeout()是大家再熟悉不过的定时器,但平时对定时器的了解甚少,于是想看看setTimeout()的原理机制. setTimeout()基础 setTimeo ...

  7. JavaScript定时器及相关面试题

    在单线程JavaScript这篇文章中,在介绍JavaScript单线程的同时,也介绍了setTimeout是如何工作的.但是对于定时器的一些内容,并没有做深入的讨论.这篇文章,会详细说说JS的两种定 ...

  8. JavaScript定时器原理分析

    .header { cursor: pointer } p { margin: 3px 6px } th { background: lightblue; width: 20% } table { t ...

  9. 初探JavaScript(三)——JS带我"碰壁"带我飞

    已经写了两篇关于小白的JavaScript之行,不可否认,每一种语言都有其精华与糟粕之处,来不及细细体味其精华奥妙,也没法对其评头论足,只能先了解,后深入.到目前为止已经看完<JavaScrip ...

随机推荐

  1. Selenium中的几种等待方式,需特别注意implicitlyWait的用法

    摘:http://blog.csdn.net/pf20050904/article/details/20052485 最近在项目过程中使用selenium 判断元素是否存在的时候 遇到一个很坑爹的问题 ...

  2. testng+reportng,运行xml

    在看了http://seleniumcn.cn/read.php?tid=7960视频的Reportng后自己实验了下, 1.下载reportng-1.1.4.zip,解压后如下,把reportng- ...

  3. android wifi Direct Audio TX/RX延迟分析

    1 Direct Audio TX代码流程 1.1 从Host到FW 1.1.1 代码流程 htc.c::HifLayerRecvCallback//从HIF_USB_CONTEXT获取数据中断,具体 ...

  4. linux Makefile编写的整理

    最近将Makefile的编写进行了整理和提炼了一下,大致分为五个步骤: 编译总共为五个部分 1.设置编译环境 set compile environment 2.获取要编译的源文件,以及把源文件转换为 ...

  5. dlmalloc(Android bionic C库的malloc实现)简介

    欢迎转载opendevkit文章, 文章原始地址: http://www.opendevkit.com/?e=56 Dlmalloc是目前一个十分流行的内存分配器,其由Doug Lea从1987年开始 ...

  6. Zabbix日志监视的汇总报警(更新发送邮件脚本)

    Zabbix的用户一定会碰到这种情况: 日志报警一般设置的是multiple模式,有错误大量写入的时候,每写入一行就会触发一次action,导致出现大量的报警邮件. 特别是ora的报警,经常一出就是上 ...

  7. PAT/简单模拟习题集(一)

    B1001.害死人不偿命的(3n+1)猜想 (15) Description: 卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉 ...

  8. iOS 视图,动画渲染机制探究

    腾讯Bugly特约作者:陈向文 终端的开发,首当其冲的就是视图.动画的渲染,切换等等.用户使用 App 时最直接的体验就是这个界面好不好看,动画炫不炫,滑动流不流畅.UI就是 App 的门面,它的体验 ...

  9. Windows Phone App的dump文件实例分析- System.ExecutionEngineException

    前言 在开始这篇文章之前我们先来讲讲如何从高度优化的Release版的Dump中找到正确的异常上下文地址,并手动恢复异常发生的第一现场. 1. 什么是异常上下文 简单来说,在windows体系的操作系 ...

  10. 打通移动App开发的任督二脉、实现移动互联创业的中国梦

    年初的两会上,第一次听到克强总理讲到“互联网+”的计划,当时就让我为之感到无比振奋.我个人的理解是:“互联网+”的本质就是要对传统行业供需双方的重构,通过移动互联技术来推动各个行业上的全民创新,促使中 ...