JS异步执行之setTimeout 0的妙用
Posted 瓜牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS异步执行之setTimeout 0的妙用相关的知识,希望对你有一定的参考价值。
最近在工作中遇到一些问题,大致是关于js执行问题的。由于没搞清执行顺序,导致出现了一些奇怪的bug。 所以这里整理一些有关异步执行的知识(冰山一角角)...
大家都知道js是单线程的,执行起来是顺序的,在顺序的业务逻辑中当然没有问题。如果遇到可以并发执行的业务逻辑,再排队就很低级了,所以需要异步执行!
1、什么是异步?
setTimeout(function(){ console.log(0); },0) console.log(1);
// 先打印 1 // 再打印 0
比方说有些饭店你去吃饭需要提前预定(异步代码执行),等其他人吃完(同步代码执行完毕)你才能去,因此在其他人吃饭的时候(同步代码执行中)你可以去干其他的事情,等其他人吃完了(同步代码执行完毕)会有人来通知你,于是你可以去了(开始执行异步代码【setTimeout/setInterval/事件处理程序/ajax回调...】的执行)。
我们回到前面那段setTimeout身上,它的工作原理是这样的,当你定义setTimeout那一刻起(不管时间是不是0),js并不会直接去执行这段代码,而是把它扔到一个事件队列里面,当页面中所有同步任务都干完了以后,才会去执行事件队列里面的代码。什么是同步,按代码顺序执行,就像音乐播放器里的顺序播放。
2、setTimeout 0的妙用
<!DOCTYPE html> <html> <head> <title> </title> <meta charset="utf-8"> </head> <body> <p> <input type="text" id="input" value=""/> <span id="preview"></span> </p> </body> <script type="text/javascript"> (function(){ function $(id){ return document.getElementById(id); } $(\'input\').onkeypress = function(){ $(\'preview\').innerHTML = this.value; } })(); </script> </html>
这个keypress函数原意是监听到用户输入字符串就将其完整的显示出来,但是奇怪的是最后一个字符串总是没能显示出来:
重点来了,使用setTimeout 0来解决:
$(\'input\').onkeypress = function(){ setTimeout(function(){ $(\'preview\').innerHTML = $(\'input\').value;},0); }
好的,问题就这样解决了,首先回过头来看看问题是如何产生的?
代码中,我们用到的事件是keypress,而keypress事件发生时,dom元素的状态还未改变,keypress事件之后dom元素的状态才发生改变,通过setTimeout 0延迟执行就能达到期望的结果了。当然,不用setTImeout 0 ,直接用onkeyup亦可。
但是setTimeout有些小小的问题,就是时间不精确:
<!DOCTYPE html> <html> <head> <meta name="generator" content=""> <title></title> <meta charset="utf-8"> </head> <body> <h2>未使用 <code>setTimeout</code></h2> <button id="makeinput">生成 input</button> <p id="inpwrapper"></p> </body> <script type="text/javascript"> (function(){ function get(id){ return document.getElementById(id); } function log(a){ console.log(a) } 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.onfocus=function(){ //给生成的input绑定focus事件 log("iptFocus"); } input.focus(); log("down"); } get(\'makeinput\').onfocus = function(){ log("btnFocus"); } get(\'makeinput\').onclick = function(){ log("click"); } get(\'makeinput\').onmouseup=function(){ log("up"); } } })(); </script> </html> // 打印 iptFocus // 打印 down // 打印 btnFocus 导致新增的input无焦点的真凶 // 打印 up // 打印 click
将 input.focus(); 改为 setTimeout(function(){input.focus();},0);得到结果为:
// 打印 down // 打印 btnFocus // 打印 iptFocus 鬼知道为什么会跑到这执行 // 打印 up // 打印 click
理解了js的异步执行和setTImeout 0的工作原理,能更好的方便我们解决工作中的bug...
以上是关于JS异步执行之setTimeout 0的妙用的主要内容,如果未能解决你的问题,请参考以下文章