【js】关于 setTimeout(0)所引发的……
2016-07-14 20:07
453 查看
在看vue的时候,看到了vue关于异步更新的原理,里面提到了setTimeout(0)。于是我想起来之前面试的时候被问过这个问题,并且在很久之后我随便查了查敷衍了事= =,到底是敷衍谁。于是昨天又去google了一下这个问题……果然发现了很多不得了的事(笑哭)。
之前知道,js是单线程的,所以在一段时间内只能执行一个任务。然后我们又知道settimeout和setinterver都是存在时延的,因为可能在计时器到达时间后,线程正在做其他的任务。所以要等到这个任务结束了才开始执行回调函数。我以为是因为这样,所以settimeout(0)由于时延,导致了在下一条语句之后才能执行。
。回想了下,那时候用的是百度,以后一定要告别度娘……
首先要说的一个是,现代浏览器一般要求settimeout这样的定时器,时延时间在4毫秒以上,如果小于4毫秒,就要往上加。(另外对于setInterval,H5规定最少时间为10毫秒)所以之前的理解从一定程度上……没什么问题TAT。
但是如果从一个稍微复杂的情况下去分析,那就可以发现……这个问题下的js机制相关的问题了。
以下是例子:
例子
这是比较多引用的一个例子,源码在这儿:
这时候提到js的执行机制:event loop。
浏览器最起码有三个线程,js线程,GUI线程,浏览器事件触发线程。js线程和GUI线程是互斥的,当页面需要渲染(回流,重绘等)的时候,js线程就挂起。js执行的时候GUI线程就先缓存。浏览器事件触发捕获相关事件,然后把事件加入到js事件队列尾部。
把js线程看做一个队列,里面执行的都是同步的任务。对于异步的任务,当异步的任务到了可以执行的时候(比如事件触发了,计时器的时间到了),就把这个任务取出来加到一个队列里面。当主线程中的任务执行完了,就到这个异步队列里面取任务执行。
如上所述的过程就是一个事件循环的过程,一系列event事件做完了,再取异步的队列做。做完了再来一轮。(我觉得是按时间顺序,然后先处理同步事件,再处理异步事件这样)
所以上面那个例子,没有执行select()和focus()只是因为执行之后,btn.focus又重新占据了焦点。
关于settimeout(0),我之前一直以为是像++x++这样有点无趣,有点变态地考察知识点的方式。然而其实人家还是有正经用途的。由于事件循环机制,可以利用settimeout(0)实现异步,并且可以改变一些事件实现的顺序。比如在用promise的时候,通过设置settimeout(0)把同步的调用变成异步的。详情可以参见promise指南中的例子
参考资料:
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
http://www.cnblogs.com/xieex/archive/2008/07/11/1241137.html
http://www.cnblogs.com/silin6/p/4333999.html
http://www.cnblogs.com/zhaodongyu/p/3922961.html
http://javascript.ruanyifeng.com/bom/timer.html#toc3
之前知道,js是单线程的,所以在一段时间内只能执行一个任务。然后我们又知道settimeout和setinterver都是存在时延的,因为可能在计时器到达时间后,线程正在做其他的任务。所以要等到这个任务结束了才开始执行回调函数。我以为是因为这样,所以settimeout(0)由于时延,导致了在下一条语句之后才能执行。
。回想了下,那时候用的是百度,以后一定要告别度娘……
首先要说的一个是,现代浏览器一般要求settimeout这样的定时器,时延时间在4毫秒以上,如果小于4毫秒,就要往上加。(另外对于setInterval,H5规定最少时间为10毫秒)所以之前的理解从一定程度上……没什么问题TAT。
但是如果从一个稍微复杂的情况下去分析,那就可以发现……这个问题下的js机制相关的问题了。
以下是例子:
例子
这是比较多引用的一个例子,源码在这儿:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>setTimeout</title> <script type="text/javascript" > (function(){ function get(id){ return document.getElementById(id); } window.onload = function(){ get('makeinput').onmousedown = function(){ var input = document.createElement('input'); input.setAttribute('type', 'text'); input.setAttribute('value', 'test1'); get('inpwrapper').appendChild(input); input.focus(); input.select(); } get('makeinput2').onmousedown = function(){ var input = document.createElement('input'); input.setAttribute('type', 'text'); input.setAttribute('value', 'test1'); get('inpwrapper2').appendChild(input); setTimeout(function(){ input.focus(); input.select(); }, 0); } get('input1').onkeypress = function(){ get('preview1').innerHTML = this.value; } get('input2').onkeypress = function(){ setTimeout(function(){ get('preview2').innerHTML = get('input2').value; },0 ); } } })(); </script> </head> <body> <h1><code>DEMO1</code></h1> <h2>1、未使用 <code>setTimeout</code>(未选中文本框内容)</h2> <button id="makeinput">生成 input</button> <p id="inpwrapper"></p> <h2>2、使用 <code>setTimeout</code>(立即选中文本框内容)</h2> <button id="makeinput2">生成 input</button></h2> <p id="inpwrapper2"></p> -------------------------------------------------------------------------- <h1><code>DEMO2</code></h1> <h2>1、未使用 <code>setTimeout</code>(只有输入第二个字符时,前一个字符才显示出来)</h2> <input type="text" id="input1" value=""/><div id="preview1"></div> <h2>2、使用 <code>setTimeout</code>(输入时,字符同时显示出来)</h2> <input type="text" id="input2" value=""/><div id="preview2"></div> </body> </html>看了这个例子觉得很神奇,但是看到原文得出的结论觉得匪夷所思。结论认为,在第一个例子,onmousedown的时候,由于单线程,在执行onmousedown,所以就抛弃了focus和select。这个说法显然是非常不正确的。
这时候提到js的执行机制:event loop。
浏览器最起码有三个线程,js线程,GUI线程,浏览器事件触发线程。js线程和GUI线程是互斥的,当页面需要渲染(回流,重绘等)的时候,js线程就挂起。js执行的时候GUI线程就先缓存。浏览器事件触发捕获相关事件,然后把事件加入到js事件队列尾部。
把js线程看做一个队列,里面执行的都是同步的任务。对于异步的任务,当异步的任务到了可以执行的时候(比如事件触发了,计时器的时间到了),就把这个任务取出来加到一个队列里面。当主线程中的任务执行完了,就到这个异步队列里面取任务执行。
如上所述的过程就是一个事件循环的过程,一系列event事件做完了,再取异步的队列做。做完了再来一轮。(我觉得是按时间顺序,然后先处理同步事件,再处理异步事件这样)
所以上面那个例子,没有执行select()和focus()只是因为执行之后,btn.focus又重新占据了焦点。
关于settimeout(0),我之前一直以为是像++x++这样有点无趣,有点变态地考察知识点的方式。然而其实人家还是有正经用途的。由于事件循环机制,可以利用settimeout(0)实现异步,并且可以改变一些事件实现的顺序。比如在用promise的时候,通过设置settimeout(0)把同步的调用变成异步的。详情可以参见promise指南中的例子
参考资料:
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
http://www.cnblogs.com/xieex/archive/2008/07/11/1241137.html
http://www.cnblogs.com/silin6/p/4333999.html
http://www.cnblogs.com/zhaodongyu/p/3922961.html
http://javascript.ruanyifeng.com/bom/timer.html#toc3