javascript真的是异步的吗?且看setTimeout的实现原理以及setTimeout(0)的使用场景「建议收藏」

javascript真的是异步的吗?且看setTimeout的实现原理以及setTimeout(0)的使用场景

大家好,又见面了,我是全栈君。

在今天之前我一直以为setTimeout这个函数是异步的,无意中看到了一篇关于setTimeout的文章。发现自己曾经的认识全是错误的,赶紧总结下。


先看一段代码:

var start = new Date();
setTimeout(function(){
    var end = new Date();
    console.log("Time elapsed: ", end - start, "ms");
}, 500);

while (new Date - start <= 1000)
{

}

运行这段脚本能够看到:Time elapsed的值大概在1001ms左右,肯定会超过1000ms。也就是说:setTimeout失效了,指定的函数并没有在500ms后运行。而是延迟到1000ms后才运行。


再看一段代码:

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

执行这段脚本能够看到:先打印2后打印1,我们在setTimeout里面指定了0ms,希望能马上执行,可是实际上没有效果。


想要理解上面的2段代码,我们得了解一下javascript中setTimeout的实现原理。首先牢记一点:JavaScript 是单线程运行的,也就是无法同一时候运行多段代码。

以下这段解释来自这篇博客

        JavaScript是单线程运行的,无法同一时候运行多段代码。当某一段代码正在运行的时候,全部兴许的任务都必须等待,形成一个队列。

一旦当前任务运行完毕,再从队列中取出下一个任务,这也常被称为 “堵塞式运行”。所以一次鼠标点击,或是计时器到达时间点,或是Ajax请求完毕触发了回调函数。这些事件处理程序或回调函数都不会马上运行,而是马上排队。一旦线程有空暇就运行。假如当前 JavaScript线程正在运行一段非常耗时的代码,此时发生了一次鼠标点击。那么事件处理程序就被堵塞。用户也无法马上看到反馈。事件处理程序会被放入任务队列。直到前面的代码结束以后才会開始运行。假设代码中设定了一个 setTimeout,那么浏览器便会在合适的时间。将代码插入任务队列。假设这个时间设为 0,就代表马上插入队列,但不是马上运行。仍然要等待前面代码运行完成。

所以 setTimeout 并不能保证运行的时间。是否及时运行取决于 JavaScript 线程是拥挤还是空暇。


也就是说setTimeout仅仅能保证在指定的时间过后将任务(须要运行的函数)插入队列等候,并不保证这个任务在什么时候运行。运行javascript的线程会在空暇的时候,自行从队列中取出任务然后运行它。javascript通过这样的队列机制。给我们制造一个异步运行的假象。

var start = new Date();
setTimeout(function(){
    var end = new Date();
    console.log("Time elapsed: ", end - start, "ms");
}, 500);

console.log("task finished.");

我们之所以会感觉到这段代码是在异步运行,这是由于javascript线程并没有由于什么耗时操作而堵塞,所以能够非常快地取出排队队列中的任务然后运行它。

如今我们知道了setTimeout的原理了,如今看下setTimeout(0)的使用场景。以下这个样例来自这篇文章

<input type="text" onkeydown="show(this.value)">
<div></div>
<script type="text/javascript">
  function show(val) {
    document.getElementsByTagName('div')[0].innerHTML = val;
  }
</script>

这里绑定了 keydown 事件,意图是当用户在文本框里输入字符时。将输入的内容实时地在 <div> 中显示出来。可是实际效果并不是如此,能够发现。每按下一个字符时,<div> 中仅仅能显示出之前的内容,无法得到当前的字符。

<input type="text" onkeydown="var self=this; setTimeout(function() {show(self.value)}, 0)">
<div></div>
<script type="text/javascript">
  function show(val) {
    document.getElementsByTagName('div')[0].innerHTML = val;
  }
</script>

这段代码使用了setTimeout(0)就能够实现需要的效果了。

这里事实上涉及2个任务,1个是将键盘输入的字符回写到输入框中。一个是获取文本框的值将其写入div中。第一个是浏览器自身的默认行为。一个是我们自己编写的代码。非常显然。必需要先让浏览器将字符回写到文本框。然后我们才干获取其内容写到div中。改变顺序,这这正是setTimeout(0)的作用。


參考文章:setTimeout(0) 的作用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/116141.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Python 语法错误:“SyntaxError: invalid character in identifier“,原因及解决方法

    Python 语法错误:“SyntaxError: invalid character in identifier“,原因及解决方法SyntaxError:invalidcharacterinidentifier错误翻译语法错误:标识符中的无效字符。报错信息指着的位置有问题,报错了。原因一:冒号后面有制表符。原因二:或者第3行开头是制表符。python的缩进是4个空格,不能识别制表符。注:跟中文英文空格一点关系都没有!跟中文英文空格一点关系都没有!

    2022年6月23日
    174
  • oracle绑定变量使用方法总结_绑定变量不存在

    oracle绑定变量使用方法总结_绑定变量不存在Stringsql=“select*fromuserswhereusername=?andpwd=?”;pstat=con.prepareStatement(sql);pstat.setString(1,username);pstat.setString(2,pwd);rs=pstat.executeQuery(sql);//后面发现这句写错了System.ou…

    2022年9月3日
    2
  • MATLAB 相机标定(单目)使用工具箱TOOLBOX_calib[通俗易懂]

    MATLAB 相机标定(单目)使用工具箱TOOLBOX_calib[通俗易懂]环境MATLABR2014a+windows764位1.单目摄像机标定(1)首先把解压的TOOLBOX_calib文件夹的路径设置到MATLAB里,在主页-&gt;环境-&gt;设置路径-&gt;选择工具箱路径,如图:然后保存,关闭(2)此时,将你采集到的图片放到工具箱以外的文件夹中,在MATLAB中打开,如图:注意上面的路径,必须选择图像所在的文件夹,不然下一步会出现错误“Noimage…

    2022年5月22日
    35
  • k8s基础知识_lable

    k8s基础知识_lable文章目录第三章 资源管理(续)15 命令式对象管理16 命令式对象配置17 声明式对象配置18 资源管理小结第四章 实战入门19 Namespace4.1.1 **查看**4.1.2 **创建**4.1.3 **删除**4.1.4 **使用配置文件(.yaml)进行管理**20 Pod4.2.1 创建并运行4.2.2 查看pod信息4.2.3 访问Pod4.2.4 删除指定Pod4.2.5 配置操作21 Lable4.3.1 命令方式4.3.2 配置方式22 Deployment4.4.1 命令操作4.4.

    2022年8月11日
    2
  • mysql decimal php,PHP中的MySQL DECIMAL处理

    mysql decimal php,PHP中的MySQL DECIMAL处理如通常讨论的那样(例如Storing0.00001inMySQL),DECIMAL数据类型应用于需要精确度/正确性的字段,例如帐户余额.但是,我想知道PHP如何处理这些值,以及如果它们在内部以浮点数进行处理,那么从数据库读取这些值,进行一些计算并再次写回它们时是否仍然存在问题.如果是这样,我们如何才能迫使PHP保持精度?解决方法:该变量可能是最初在PHP中的字符串(从MySQL结果对象读取时…

    2022年7月17日
    8
  • 使用reaver傻瓜式破解wifi之利用路由器WPS漏洞[通俗易懂]

    使用reaver傻瓜式破解wifi之利用路由器WPS漏洞[通俗易懂]跟这篇破解教程一样,网上破解教程多是基于路由器的WPS漏洞破解,但是这样的路由器只占少数。一般wifi是依据WPA/WPA2加密的,因此想要破解一般的wifi,还得破解这个协议,虽然近期这个协议也被破解了,不过也是很不容易的。刚入门破解,不是很熟悉,在网上找各种破解资料,终于破解成功了临近工作室的wifi,沾沾自喜~本文破解wifi针对一些路由器的WPS(Wi-fipro…

    2022年5月7日
    319

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号