关于setTimeout的知识点以及setTimeout(0)的使用场景

试试以下例子:

<!DOCTYPE html>
<html>
<head>
    <title>demo</title>
</head>
<body>

<input type="text" onkeydown="show()">
<script type="text/javascript">
  function show(val) {
      setTimeout( () => {
          console.log('inner',document.getElementsByTagName('input')[0].value)
      },0)
      console.log('outer',document.getElementsByTagName('input')[0].value)
  }
</script>
</body>
</html>

输出结果如下:

当把事件名改成keyup的时候,输入和input的value值就是同步的:

<input type="text" onkeyup="show()">
<script type="text/javascript">
  function show(val) {
      setTimeout( () => {
          console.log('inner',document.getElementsByTagName('input')[0].value)
      },0)
      console.log('outer',document.getElementsByTagName('input')[0].value)
  }

这种现象很奇怪,查阅资料,发现如下解释,源自这篇帖子

三者在事件的响应上还有一点不同,就是onkeydown 、onkeypress事件响应的时候输入的字符并没有被系统接受,而响应onkeyup的时候,输入流已经被系统接受。由于onkeydown 比onkeypress先执行,再根据上面的例子可以知道,onkeydown 触发的时候输入流正要进入系统,也就是说onkeydown 事件一完,输入流就进入了系统,无法改变。所以通过onkeydown 事件可以改变用户是按了哪个键;而onkeypress事件则是在输入流进入系统后触发的,但输入流暂未被系统处理,此时已经不能改变输入流了;onkeyup则是输入流被系统处理后发生的。

这时候setTimout发挥了它的作用,使我们能实现keydown实时取到我们输入的值。但是它的工作原理是什么呢?以下内容源自这篇帖子

先看一段代码:

function a()
{
	setTimeout(function(){console.log(1);},0);
	console.log(2);
}
a();

执行结果是先打印2,再打印1。

我们发现,setTimout设置立即执行也并不会像我们想象中的立即执行,这跟javascript的运行机制有关:JavaScript 是单线程执行的,也就是无法同时执行多段代码。

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

也就是说setTimeout只能保证在指定的时间过后将任务(需要执行的函数)插入队列等候,并不保证这个任务在什么时候执行。执行javascript的线程会在空闲的时候,自行从队列中取出任务然后执行它。

猜你喜欢

转载自blog.csdn.net/qq_42144899/article/details/89708833