为什么setTimeout(fn, 0) 会起作用?
来源:互联网 发布:cf英雄武器抽奖 软件 编辑:程序博客网 时间:2024/06/05 21:18
就这个问题,我通过详细记录浏览器的工作过程并展示settimeout()是怎么起作用的。它看起来有很长但事实上非常简单和直观,我仅仅是让它更详细而已。
更新:我已经制作了一个JSFiddle的在线实例解释如下:http://jsfiddle.net/C2YBE/31/ .
------------------------
详细:
想象网页上有一个按钮为“do somthing”和一个结果区。
do somthing上绑定的一个事件方法名字叫“LongCalc”,它完成两件事:
1.做一个长时间的计算(比如3分钟)
2.打印结果到结果区。
现在,你的用户开始测试,点击“do something”按钮,但是也没好像停在那什么也没干持续了3分钟,他们着急了,再次点击按钮,等待了1分钟,还是什么也没发生,然后再次点击..
这个问题很明显,你需要一个状态的div,用于显示发生了什么。让我们看看它是怎么工作的。
----------------------
所以你增加了一个状态DIV(初始为空),并修改点击事件“LongCalc”做了4件事:
1. 将状态“Calculating...may take 3 minutes” into status DIV.
2. 执行一个长计算
3. 打印计算结果到结果区。
4. 将状态“Calculation done”放进状态的DIV.
之后,你很高兴的讲应用交给用户测试。
他们非常生气的回来了。说当他们点击按钮的时候,这个状态的DIV从来就没有更改为“Calculating”。
-------------------------
你抓狂了,在StackOverflow上提问,或者google,并意识到这个问题:
浏览器将所有的事件类的TODO任务(包括UI任务和javascipt命令)放进一个单一队列。并且很不幸的,重绘状态的有“Calculating...”字符的DIV是一个分离的TODO,而且将会放置到队列的最后。
下面是当你的用户测试的事件的统计,每一个事件的队列中的内容。
.Queue:[空]
.Event:点击按钮。队列数组:[执行onclick(lines1-4)];
.Event:执行onclick方法的第一行代码(改变状态DIV的值)。队列数组:[执行onclick的(line2-4),重绘状态DIV为“Calculating”].请注意当DOM改变是即刻的,但重绘对应的DOM元素却需要一个新的事件并触发DOM改变,这个事件就会放置到队列的后面。
.PROBLEM!!PROBLEM!!,下面将解释。
.EVENT:执行第二行代码(calulation).队列数组:[执行onclick(lines 3-4),重绘状态DIV为“Calculating”]。
.EVENT:执行第三行代码(处理result 的DIV)。队列数组:[执行onclick(lines 4),重绘状态DIV为“Calculating,重绘结果DIV]。
.EVENT:执行第四行代码(状态div显示为"DONE").队列数组:[执行onclick(lines 4),重绘状态DIV为“Calculating,重绘结果DIV,重绘状态DIV为“DONE”]。
.EVENT(假的):onclick的子函数完成。我们把onclick移除队列并开始执行下一个。
.NOTE:从我们已经完成了计算,3分钟已经过去了。重绘工作还是没有发生。
.EVENT:重绘状态DIV为“Calculating”.我们做重绘并且从队列中移除。
.EVENT:重绘结果DIV为对应的结果,我们做重绘并且从队列中移除。
.EVENT:重绘状态DIV为“DONE”.我们做重绘并且从队列中移除。
眼尖的人很可能会看见状态DIV里一闪"Calculating",会在计算完成的时候
所以,这个潜在的问题是重绘的事件被放到了队列的最后,在执行line2事件的时候花费了3分钟,所以真正的重绘直到计算完成才会执行。
------------------------
解决的办法是setTimeout().是怎么起作用的呢?因为通过settimeout调用长执行代码,你实际上创建了2个events:settimeout执行它自己,之后0timeout后,长代码将被执行。
所以,解决你的问题,修改onclick为两块。
1.放置状态"Calculating...may take 3 minutes" 到状态DIV
2.执行包含“LongCalc”方法的0延迟的settimout。(LongCalc function is almost the same as last time but obviously doesn't have "Calculating..." Status DIV update as first step, and instead starts the calculation right away.)
所以,那现在event的顺序和这个队列的是个什么样子?
.Queue:[empty].
.Event:点击按钮:队列数组:[执行onclick(状态更新,调用setimeout)].
.Event:执行第一行(改变状态Div的值)。队列数组:[执行onclick(调用setimeout),重绘 状态 DIV为"Calculating"值]。
.Event:执行第二行代码(setTimeout),队列数组:[重绘 状态 DIV为"Calculating"值].队列将不会有新东西在0秒内。
.Event:0秒后,时钟将停止。队列数组:[重绘 状态 DIV为"Calculating"值],执行LongCalc(line 1-3)].
.Event:重绘状态区"Calculating".队列数组:[执行LongCalc(line 1-3)].
请注意这次重绘可能事实上在时钟停止前,重绘也能正常工作。
好了。在计算开始前,状态DIV将更新为"Calculating..."
原文地址:http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful
- 为什么setTimeout(fn, 0) 会起作用?
- JavaScript下的setTimeout(fn,0)意味着什么?
- JavaScript下的setTimeout(fn,0)意味着什么?
- 理解JavaScript的单线程运行机制及setTimeout(fn,0)
- JavaScript下的setTimeout(fn,0)意味着什么?
- 为什么谱聚类方法能够起作用?
- 为什么setBackground没有起作用的呢。
- webpack的配置文件为什么没起作用?
- 为什么软件外包不再“起作用”了
- setTimeout(fn, 15)这样的东西到底有没有意义?
- visibility:hidden的元素绑定click event会起作用吗
- 子元素margin-top,为什么对父元素也起作用?
- log4j.properties这个文件为什么放到src目录下就能起作用
- setTiemout(fn,0) 用法。
- $.fn
- fn
- $.fn
- 为什么会打嗝?
- HDU1839
- 基于catalog 创建RMAN存储脚本
- iOS开发进阶精华贴索引
- oracle安全有关的对象
- ExecutorService与Executors例子的简单剖析
- 为什么setTimeout(fn, 0) 会起作用?
- NSArray打印对象
- I - Dirichlet's Theorem on Arithmetic Progressions(1.5.5)
- POJ3190 Stall Reservations 贪心
- uva 755(排序、检索)
- IT运维问道---文启
- linux下unordered_map和map在小数据下性能差异
- Linux内核通知链模块
- 加载gif图片