settimeout(0) 的作用解析

大家都知道 JavaScript 中的 setTimeout() 可用来延迟执行一段代码,如:

setTimeout( function() {
  alert("Hello World");
}, 1000) //延时1秒

今天在网上看到了 setTimeout(fn, 0) 的用法,感到有些疑惑,不明白它和直接执行 fn() 有什么区别,遂去搜集了一下相关的资料,顺便分享分享。

先看一段代码:

function a() {
  setTimeout( function(){
    alert(1)
  }, 0);
  alert(2);
}
a();

代码中的 setTimeout 设为 0,也就是延迟 0ms,看上去是不做任何延迟立刻执行,即依次弹出 “1”、“2”。但实际的执行结果确是 “2”、“1”。其中的原因得从 setTimeout 的原理说起:

JavaScript 是单线程执行的,也就是无法同时执行多段代码,当某一段代码正在执行的时候,所有后续的任务都必须等待,形成一个队列,一旦当前任务执行完毕,再从队列中取出下一个任务。这也常被称为 “阻塞式执行”。所以一次鼠标点击,或是计时器到达时间点,或是 Ajax 请求完成触发了回调函数,这些事件处理程序或回调函数都不会立即运行,而是立即排队,一旦线程有空闲就执行。假如当前 JavaScript 进程正在执行一段很耗时的代码,此时发生了一次鼠标点击,那么事件处理程序就被阻塞,用户也无法立即看到反馈,事件处理程序会被放入任务队列,直到前面的代码结束以后才会开始执行。如果代码中设定了一个 setTimeout,那么浏览器便会在合适的时间,将代码插入任务队列,如果这个时间设为 0,就代表立即插入队列,但不是立即执行,仍然要等待前面代码执行完毕。所以setTimeout 并不能保证执行的时间,是否及时执行取决于 JavaScript 线程是拥挤还是空闲。

至于这样的写法有什么作用,看下面的例子。



这里绑定了  keydown  事件,意图是当用户在文本框里输入字符时,将输入的内容实时地在
中显示出来。 但是实际效果并非如此

可以发现,每按下一个字符时,

中只能显示出之前的内容,无法得到当前的字符。这时就可以利用 setTimeout(0)

原因是,当用户按下按键的时候,JavaScript 引擎需要执行 keydown 的事件处理程序,然后更新文本框的 value 值,这两件事也需要按顺序来,事件处理程序执行时,更新 value 值的任务则进入队列等待。所以我们在 keydown 的事件处理程序里是无法得到更新后的 value 的,利用 setTimeout,我们把取 value 的操作放入队列,放在更新 value 值以后,这样便达到了目的。示例如下,可以发现已经能够实时显示输入的内容。


有人可能会想到利用绑定 keyup 事件来解决,但是 onkeyup 有一个问题,就是当一直按着某个键不放时,也会无法得到输入内容,因为此时不断地触发keydown 和 keypress,直到用户松起时才会触发 keyup。当然,示例所用的keydown 也存在一些小缺点,比如用户如果使用右键粘贴,则无法得到粘贴的内容。

所以最理想的方案应该是使用 HTML5 的 input 事件,当文本框或 textarea 的value 发生变化时,就会触发此事件,对粘贴也可以很好地兼容。至于 IE9 之前的浏览器,需要使用专有的 onpropertychange 事件。


settimeout(0)就起到了一个将事件加入到队列中,待执行的一个功能效果!



你可能感兴趣的:(settimeout(0) 的作用解析)