setTimeout用法在实际项目中还是会时常遇到。比如浏览器会聪明的等到一个函数堆栈结束后才改变DOM,如果再这个函数堆栈中把页面背景先从白色设为红色,再设回白色,那么浏览器会认为DOM没有发生任何改变而忽略这两句话,因此我们可以通过setTimeout把“设回白色”函数加入下一个堆栈,那么就可以确保背景颜色发生过改变了(虽然速度很快可能无法被察觉)。

  总之,setTimeout增加了Javascript函数调用的灵活性,为函数执行顺序的调度提供极大便利。

然后,我们从基础的层面来看看:理解JavaScript的定时器是如何工作的是非常重要的。

计时器的执行常常和我们的直观想象不同,那是因为JavaScript引擎是单线程的。我们先来认识一下下面三个函数是如何控制计时器的。

var id = setTimeout(fn, delay); - 初始化一个计时器,然后在指定的时间间隔后执行。该函数返回一个唯一的标志ID(Number类型),我们可以使用它来取消计时器。

var id = setInterval(fn, delay); - 和setTimeout有些类似,但它是连续调用一个函数(时间间隔是delay参数)直到它被取消。

clearInterval(id);, clearTimeout(id); - 使用计时器ID(setTimeout 和 setInterval的返回值)来取消计时器回调的发生

有一个基本的概念你得记住了:

时间延迟不能被保证。什么意思,就是说你这样写setTimeout(fn, 500)并不代表fn肯定在500毫秒之后马上就执行,延迟很可能会更长。因为 JavaScript 是单线程语言,所有的异步事件(包括计时器、鼠标事件或者一个 XMLHttpRequest 完成)仅仅当程序执行期间有缺口的时候才会执行,不是你规定了什么时候就什么时候执行,要知道程序员不是万能的,你写的东西最终还是要看浏览器脸色的。

用一个很好的图表加以说明:

JavaScript引擎用单线程运行也是有意义的,单线程不必理会线程同步这些复杂的问题,问题得到简化.

那么单线程的JavaScript引擎是怎么配合浏览器内核处理这些定时器和响应浏览器事件的呢?
下面结合浏览器内核处理方式简单说明.

浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步.假如某一浏览器内核的实现至少有三个常驻线 程:javascript引擎线程,界面渲染线程,浏览器事件触发线程,除些以外,也有一些执行完就终止的线程,如Http请求线程,这些异步线程都会产 生不同的异步事件,下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的.虽然每个浏览器内核实现细节不同,但这其中的 调用原理都是大同小异.

由图可看出,浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可以源自 JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发 器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线 程关系,这些任务得进行排队,一个接着一个被引擎处理.

IE8及其之前的IE版本更新间隔为15.6毫秒。假设你设定的setTimeout延迟为16.7ms,那么它要更新两个15.6毫秒才会该触发延时。这也意味着无故延迟了 15.6 x 2 - 16.7 = 14.5毫秒。

16.7ms
DELAY: |------------|

CLOCK: |----------|----------|
         15.6ms    15.6ms

所以即使你给setTimeout设定的延时为0ms,它也不会立即触发。目前Chrome与IE9+浏览器的更新频率都为4ms(如果你使用的是笔记本电脑,并且在使用电池而非电源的模式下,为了节省资源,浏览器会将更新频率切换至于系统时间相同,也就意味着更新频率更低)。

退一步说,假使timer resolution能够达到16.7ms,它还要面临一个异步队列的问题。因为异步的关系setTimeout中的回调函数并非立即执行,而是需要加入等待队列中。但问题是,如果在等待延迟触发的过程中,有新的同步脚本需要执行,那么同步脚本不会排在timer的回调之后,而是立即执行

让我们用一个例子来阐明setTimeout和setInterval之间的区别:

setTimeout(function(){
    /* Some long block of code... */
    setTimeout(arguments.callee, 10);
  }, 10);
  
  setInterval(function(){
    /* Some long block of code... */
  }, 10);

这两句代码乍一看没什么差别,但是它们是不同的。setTimeout回调函数的执行和上一次执行之间的间隔至少有10ms(可能会更多,但不会少于10ms),而setInterval的回调函数将尝试每隔10ms执行一次,不论上次是否执行完毕。

在这里我们学到了很多知识,总结一下:

JavaScript引擎是单线程的,强制所有的异步事件排队等待执行

setTimeout 和 setInterval 在执行异步代码的时候有着根本的不同

如果一个计时器被阻塞而不能立即执行,它将延迟执行直到下一次可能执行的时间点才被执行(比期望的时间间隔要长些)

如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔。

参考:

一家之言:说说 JavaScript 计时器的工作原理_大前端

http://www.daqianduan.com/1112.html

JavaScript的单线程性质以及定时器的工作原理 - Rain man - PHP博客

http://www.phpweblog.net/rainman/archive/2009/01/05/6267.html

JavaScript可否多线程? 深入理解JavaScript定时机制 - 前端交互 - PHP5研究室

http://www.phpv.net/html/1700.html

 

转载于:https://www.cnblogs.com/answercard/p/3852795.html

Javascript引擎单线程机制及setTimeout执行原理说明相关推荐

  1. Javascript 引擎工作机制(js层面梳理)

    转载地址:http://www.jb51.net/article/98610.htm 我们需要引入几个相关的概念:执行环境栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链等,这些概念正是J ...

  2. javascript引擎工作原理的初步了解

    From:https://segmentfault.com/a/1190000014242281 Javascript引擎是能运行javascript代码的程序或解释器.做为前端开发人员,了解java ...

  3. JavaScript变量提升机制

    JavaScript变量提升机制 Js代码执行前(栈内存)还做了一件事那就是变量提升,Js会在所有var function等关键字的提前声明或者定义.. 看以下的代码: console.log(a); ...

  4. javascript引擎执行的过程的理解--执行阶段

    一.概述 js引擎执行过程主要分为三个阶段,分别是语法分析,预编译和执行阶段,上篇文章我们介绍了语法分析和预编译阶段,那么我们先做个简单概括,如下: 1.语法分析: 分别对加载完成的代码块进行语法检验 ...

  5. JavaScript引擎工作原理解析

    JavaScript引擎是什么 想知道JavaScript引擎是什么,首先要知道JavaScript(简称js)是什么,相信对于屏幕前的你来说,js是干什么的已经不用再多说,但还是有必要介绍下Java ...

  6. 解秘 Node.js 单线程实现高并发请求原理,以及串联同步执行并发请求的方案

    最近在做一个支持多进程请求的 Node 服务,要支持多并发请求,而且请求要按先后顺序串联同步执行返回结果. 对,这需求就是这么奇琶,业务场景也是那么奇琶. 需求是完成了,为了对 Node.js 高并发 ...

  7. JAVA类加载对字节码的处理_深入理解Java虚拟机(类文件结构+类加载机制+字节码执行引擎)...

    [本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 周志明的< ...

  8. JavaScript高级 浏览器的渲染原理与JavaScript代码执行原理

    浏览器的渲染原理 1. 网页的解析过程 2. 浏览器内核 1. V8引擎 3. 浏览器渲染过程 1. HTML解析 2. 生成CSS规则 3. 构建Render Tree 4. 布局(layout) ...

  9. 正则表达式引擎执行原理——从未如此清晰!

    目前越来越多的网站.编辑器.编程语言都已支持一种叫"正则表达式"的字符串查找"公式",有过编程经验的同学都应该了解正则表达式(Regular Expressio ...

最新文章

  1. 妙用QTP F1帮助功能
  2. 两个函数彻底理解Lua中的闭包
  3. 遭遇ORA-01200错误的原因及解决方法
  4. linux系统下一个冷门的RAID卡ioc0及其监控mpt-status
  5. 《系统集成项目管理工程师》必背100个知识点-81风险管理
  6. Linux安装gcc
  7. redhat 9.0 mysql 配置_RedHat 9.0下Apache+PHP+MySQL服务器安装配置
  8. LeetCode MySQL 1285. 找到连续区间的开始和结束数字(dense_rank连续排名)
  9. java 对象地址_如何获取Java对象的地址?
  10. python笔记14-读取yaml配置文件(pyyaml)
  11. Computer:路由器连接交换机怎么建立局域网
  12. ET框架---UnityWebRequestAsync学习笔记
  13. USB-HID鼠标键盘驱动
  14. 高通下载模式9008
  15. SpringCloud Netflix-Zuul使用
  16. 3种夸克有多少组合?
  17. LeetCode 1240. Tiling a Rectangle with the Fewest Squares
  18. Windwos注册表案例(友尽百科)
  19. 【AI视野·今日CV 计算机视觉论文速览 第231期】Mon, 5 Jul 2021
  20. avahi-daemon启动失败-解决方法-linux

热门文章

  1. ssh登录服务器提示错误no hostkey alg
  2. iPhone X Web 设计
  3. C++ 字符串指针与字符串数组
  4. Python:IndentationError: unexpected indent
  5. 统一管理MOSS2010用户头像
  6. 服务器磁盘操作系统双机软件集成,实战:ROSE HA双机热备系统安装指南
  7. matlab中腐蚀图像的编写,Matlab实现二值图像的腐蚀算法源代码
  8. myeclipse中如何在整个工程中搜索字符串
  9. 微信 手机 网站 开发 签名 signature node (在更新中)
  10. QC无法启动,实战记录