热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

你应当晓得的setTimeout隐秘

计时器setTimeout是我们常常会用到的,它用于在指定的毫秒数后挪用函数或盘算表达式。语法:setTimeout(code,millisec,args);注重:假如code为字

计时器setTimeout是我们常常会用到的,它用于在指定的毫秒数后挪用函数或盘算表达式。

语法:setTimeout(code, millisec, args);

注重:假如code为字符串,相当于实行eval()要领来实行code。

固然,这一篇文章并不仅仅通知你怎样用setTimeout,而且明白其是怎样实行的。

1、setTimeout道理

先来看一段代码:

var start = new Date();
var end = 0;
setTimeout(function() { console.log(new Date() - start); }, 500);
while (new Date() - start <= 1000) {}

在上面的代码中,定义了一个setTimeout定时器,延时时刻是500毫秒。

你是否是以为打印结果是: 500

可现实倒是出乎你的预料,打印结果是如许的(或许你打印出来会不一样,但肯定会大于1000毫秒):
《你应当晓得的 setTimeout 隐秘》

这是为毛呢?究其原因,这是因为 Javascript是单线程实行的。也就是说,在任何时刻点,有且只要一个线程在运转Javascript递次,没法统一时刻运转多段代码。

再来看看浏览器下的Javascript。

浏览器的内核是多线程的,它们在内核掌握下相互配合以坚持同步,一个浏览器最少完成三个常驻线程:Javascript引擎线程,GUI衬着线程,浏览器事宜触发线程。

  • Javascript引擎是基于事宜驱动单线程实行的,Javascript引擎一向守候着使命行列中使命的到来,然后加以处置惩罚,浏览器不管什么时刻都只要一个Javascript线程在运转Javascript递次。

  • GUI衬着线程担任衬着浏览器界面,当界面须要重绘(Repaint)或因为某种操纵激发回流(Reflow)时,该线程就会实行。但须要注重,GUI衬着线程与Javascript引擎是互斥的,当Javascript引擎实行时GUI线程会被挂起,GUI更新会被保存在一个行列中比及Javascript引擎余暇时立时被实行。

  • 事宜触发线程,当一个事宜被触发时,该线程会把事宜添加到待处置惩罚行列的队尾,守候Javascript引擎的处置惩罚。这些事宜可来自Javascript引擎当前实行的代码块如setTimeout、也可来自浏览器内核的其他线程如鼠标点击、Ajax异步请求等,但因为Javascript的单线程关联,所有这些事宜都得列队守候Javascript引擎处置惩罚(当线程中没有实行任何同步代码的前提下才会实行异步代码)。

到这里,我们再来回忆一下最初的例子:

var start = new Date();
var end = 0;
setTimeout(function() { console.log(new Date() - start); }, 500);
while (new Date() - start <= 1000) {}

虽然setTimeout的延时时刻是500毫秒,然则因为while轮回的存在,只要当距离时刻大于1000毫秒时,才会跳出while轮回,也就是说,在1000毫秒之前,while轮回都在占有着Javascript线程。也就是说,只要守候跳出while后,线程才会余暇下来,才会去实行之前定义的setTimeout。

末了 ,我们能够总结出,setTimeout只能保证在指定的时刻后将使命(须要实行的函数)插进去使命行列中期待,然则不保证这个使命在什么时刻实行。一旦实行Javascript的线程余暇出来,自行从行列中掏出使命然后实行它。

因为Javascript线程并没有因为何耗时操纵而壅塞,所以能够很快地掏出列队行列中的使命然后实行它,也是这类行列机制,给我们制作一个异步实行的假象。

2、setTimeout的好搭档“0”

或许你见过下面这一段代码:

setTimeout(function(){ // statement}, 0);

上面的代码示意立时实行。本意是立时实行挪用函数,但现实上,上面的代码并非立时实行的,这是因为setTimeout有一个最小实行时刻,当指定的时刻小于该时刻时,浏览器会用最小许可的时刻作为setTimeout的时刻距离,也就是说纵然我们把setTimeout的耽误时刻设置为0,被挪用的递次也没有立时启动。

差别的浏览器现实情况差别,IE8和更早的IE的时刻精确度是15.6ms。不过,跟着HTML5的涌现,在高等版本的浏览器(Chrome、ie9+等),定义的最小时刻距离是不得低于4毫秒,假如低于这个值,就会自动增添,并且在2010年及今后宣布的浏览器中采用一致。

所以说,当我们写为 setTimeout(fn,0) 的时刻,现实是完成插队操纵,请求浏览器“尽量快”的举行回调,然则现实能多快就完整取决于浏览器了。

setTimeout(fn, 0)有什么用途呢?实在用途就在于我们能够转变使命的实行递次!因为浏览器会在实行完当前使命行列中的使命,再实行setTimeout行列中积聚的的使命。

经由过程设置使命在延晚到0s后实行,就可以转变使命实行的先后递次,耽误该使命发作,使之异步实行。

来看一个网上很盛行的例子:

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);
};

`实例:实例

当你往两个表单输入内容时,你会发明未运用setTimeout函数的只会猎取到输入前的内容,而运用setTimeout函数的则会猎取到输入的内容。

这是为何呢?

因为当按下按键的时刻,Javascript 引擎须要实行 keydown 的事宜处置惩罚递次,然后更新文本框的 value 值,这两个使命也须要按递次来,事宜处置惩罚递次实行时,更新 value值(是在keypress后)的使命则进入行列守候,所以我们在 keydown 的事宜处置惩罚递次里是没法获得更新后的value的,而应用 setTimeout(fn, 0),我们把取 value 的操纵放入行列,放在更新 value 值今后,如许便可获掏出文本框的值。

未运用setTimeout函数,实行递次是:`Onkeydown=> Onkeypress=> onkeyup

运用setTimeout函数,实行递次是:Onkeydown=> Onkeypress=> function => onkeyup`

虽然我们能够运用keyup来替换keydown,不过有一些问题,那就是长定时,keyup并不会触发。

长定时,keydown、keypress、keyup的挪用递次:

keydown
keypress
keydown
keypress
...
keyup

也就是说keyup只会触发一次,所以你没法用keyup来及时猎取值。

我们还能够用setImmediate()来替换setTimeout(fn,0)

if (!window.setImmediate) {
window.setImmediate = function(func, args){
return window.setTimeout(func, 0, args);
};
window.clearImmediate = window.clearTimeout;
}

setImmediate()`要领用来把一些须要长时刻运转的操纵放在一个回调函数里,在浏览器完成后面的其他语句后,就立时实行这个回调函数,必选的第一个参数func,示意将要实行的回调函数,它并不须要时刻参数。

注重:现在只要IE10支撑此要领,固然,在Nodejs中也能够挪用此要领。

3、setTimeout的一些隐秘

3.1 setTimeout中回调函数的this

因为setTimeout() 要领是浏览器 window 对象供应的,因而第一个参数函数中的this现实上是指向window对象,这跟变量的作用域有关。

看个例子:

var a = 1;
var obj = {
a: 2,
test: function() { setTimeout(function(){ console.log(this.a); }, 0);
}
};
obj.test(); // 1

不过我们能够经由过程运用bind()要领来转变setTimeout回调函数里的this

var a = 1;
var obj = {
a: 2,
test: function() {
setTimeout(function(){
console.log(this.a);
}.bind(this), 0);
}
};
obj.test(); // 2

相干文章:JS中的call、apply、bind要领

3.2 setTimeout不止两个参数

我们都晓得,setTimeout的第一个参数是要实行的回调函数,第二个参数是耽误时刻(假如省略,会由浏览器自动设置。在IE,FireFox中,第一次配可能给个很大的数字,100ms高低,往后会缩小到最小时刻距离,Safari,chrome,opera则多为10ms高低。)

实在,setTimeout能够传入第三个参数、第四个参数&#8230;.,它们示意神马呢?现实上是用来示意第一个参数(回调函数)传入的参数。

setTimeout(function(a, b){
console.log(a); // 3
console.log(b); // 4},0, 3, 4);

原文链接:你应当晓得的 setTimeout 隐秘

假如你有疑问或发起,迎接鄙人面的批评区批评!


推荐阅读
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
author-avatar
苦蔷薇1988
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有