使用setTimeout(fn, 0)出现的一个奇怪的现象

  1. 代码

html

<p>未使用setTimeout函数</p>
<p id="one">
    <input type="text" id="input" value="">
    <span></span>
</p>
<p>使用setTimeout函数</p>
<p id="second">
    <input type="text" id="input" value="">
    <span></span>
</p>

js

document.querySelector('#one input').onkeydown = function() {
    document.querySelector('#one span').innerHTML = this.value;
}
document.querySelector('#second input').onkeydown = function() {
    setTimeout(function() {
        document.querySelector('#second span').innerHTML = document.querySelector('#second input').value;
    }, 0);
}

现象

clipboard.png

阅读 3.6k
7 个回答

onkeydown是在用户按下键盘按键时触发,之后是改变input的值,然后触发onkeyup。
所以第一种情况下,回调函数里,span元素设置的是未改变的input的value值。第二种情况是setTimeout把修改span元素的操作放在本次同步事件的后面,而这时input的值已经改变了。
如果要达到一样的效果,可以用onkeyup代替。
demo

这里其实 和 setTimeout 关系不大, 是onkeydown 事件的关系,

首先 你要 了解 这个事件

onkeydown 属性在用户(在键盘上)按键时触发
onkeypress 事件会在键盘按键被按下并释放一个键时发生。
onkeyup 事件会在键盘按键被松开时发生。

当用户在第一次按下键的时候 其实值是空, 你可以 onkeydown 事件中 打印下 this.value;

keydown 换成 keyup 就可以了,

原因:keydown->value 改变->keyup(超过一定间隔没有 keyup ,会继续 keydown ),setTimeout 有个最小间隔,导致捕获到了改变后的 value ,没有setTimeout 的时候,直接捕获的是改变前的value,测试戳 demo

通俗点说,
你输入的内容,并不是立刻赋值到this.value的,他存在一个栈顺序。
但用了setTimeout(fn, 0)以后,fn的代码会放到本次执行栈的最后去执行。

首先,延迟设置为0,也不是真正意义上的无延迟;其次,执行到 setTimeout 会加入一个单独的队列中执行,这个队列的任务在主队列没有执行完毕时都不会去执行

setTimeout延迟设置为0时,是把当前的操作放到事件队列的的最后去执行,因为此时的事件队列最后的事件其实是click事件,所以也就是click事件完成之后才执行setTimeout里的内容。

且click事件执行过程中,监听事件是keydown执行之后,接着给输入框赋值,click的后续的事件还有keyup,keyup事件之执行之后,然后才算是完成了点击事件,才从事件队列里出栈。

document.querySelector('#one input').onkeydown = function() {
        alert('one');
        document.querySelector('#one span').innerHTML = this.value;
    }
    document.querySelector('#second input').onkeydown = function() {
        alert('second1');
        setTimeout(function() {
            alert('second2');
            document.querySelector('#second span').innerHTML = document.querySelector('#second input').value;
        }, 0);
    }

中间加个alert断点就知道了
1.input在键盘按下的时候,onkeydown先执行,再有值,获取不到最后输入的值
2.input在键盘按下的时候,onkeydown也是先执行,然后触发一个异步setTimeout,值出现了之后再执行异步的setTimeout,所以能够获得最后输入的值。

onkeydown改为onkeyup就可以解决,因为onkeyup是放开按键的时候触发的,所以会先有值先执行onkeyup

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题