作为入门者来说。了解JavaScript中timer的工作方式是非常重要的。通常它们的表现行为并非那么地直观,而这是由于它们都处在一个单一线程中。让我们先来看一看三个用来创建以及操作timer的函数。

var id = setTimeout(fn, delay); 

- 初始化一个单一的timer,这个timer将会在一定延时后去调用指定的函数。这个函数(setTimeout)将返回一个唯一的ID,我们能够通过这个ID来取消timer。

var id = setInterval(fn, delay);

- 与setTimeout类似,仅仅只是它会持续地调用指定的函数(每次都有一个延时),直到timer被取消为止。

clearInterval(id);, clearTimeout(id);

- 接受一个timer的ID(由上述的两个函数返回的),而且停止timer的回调事件。

要弄明确这个定时器内部是怎么工作的,有一个非常重要的概念须要被提出来:

1 定时器延迟是不准确的(guaranteed).由于全部的javascript 浏览器代码仅仅有一个单线程运行,而且那些异步事件(如鼠标点击事件,和定时器)仅仅会在出现线程空暇的时候去会运行。这有一个图表演示。例如以下:

这里有非常多信息在这个图中须要去理解。可是全然理解它之后。你会对javascript中异步机制有一个清楚的认识。

这个图是一维的:

垂直方向我们用毫秒单位来标记这个时间。这个蓝色的方块代表这个正在被运行的javascript代码。比如,这第一个被运行的javascript代码大约花了18毫秒,这个鼠标事件块大约花费了11毫秒,等等。

由于javascript 引擎永远仅仅会执行一个片段的代码在同一个时间(由于这个单线程机制),那么这时每个代码块将会堵塞(blocking)别的异步事件的执行。

这意味着当一个异步事件被调用(比如当一个鼠标点击,一个定时器触发firing,或者一个xmlhttprequest 过程完毕),它将会被增加到队里。并延迟运行(至于详细怎样被入到队列中,不同的浏览器有不同的实现。我们这里仅仅考虑简单的情况)

从一開始,在第一个javasript中,有两个定时器被初始化了: 一个10 毫秒的 setTimeout时间和一个10 毫秒的setInterval事件(这里注意,只不过初始化,亦或叫作定义)。

由于这个定时器開始的时间和位置。导致它们在第一个javascript块完毕前就已经真正被调用(这里的调用,并不是直接运行,这里须要注意,能够理解为仅仅是准备调用,把该回调方法增加到队列)了。

注意,不管怎么样(however)。定时器都不会立马运行(由于线程没有空暇的原因,它没办法直接运行)。

相反。这个被延迟的方法会被增加到队列中,在某个能够运行的时刻(线程空暇的时刻)运行。

另外一点,在第一个javascript块中。我们能够看到另一个鼠标事件被触发了。这个javascript 回调方法被关联到一个异步事件 (没人知道用户什么时候做这个动作。所以它被觉得是异步的),这个异步事件也不会立马运行,和上面的定时器一样。也会被增加到队列中。

在第一个javascript 块运行结束之后,javascript 引擎就会立马问一个问题: 还有什么在等待被运行的代码么? 那么这个时间,有一个鼠标事件回调和定时器回调同一时候在等待。这个浏览器立即挑选一个(从图中看。是鼠标事件回调)立马运行。这个定时器继续等待,直到下一个可能的时刻。

注意一点:在这个这个鼠标事件处理函数正在被运行的同一时候,第一个interval 回调函数也会调用。

正如前面提到的定时器一样,它的回调方法会被增加到队列中。

然而。注意当这个interval再一次被调用(这个时候这个定时器的回调方法正在被运行)。那么这个时候。这个interval 的回调方法将会被删除(drop)。

假设因为主线程须要运行非常长时间的代码块,导致你在队列中增加了非常多个回调方法,那么当这个主线程结束之后,一连串的回调函数连续运行没有间隔,直到结束。比較好的做法,是临时让浏览器歇息等待一会。让队列中没有Interval回调。

我们在看到一些情况:在第三个interval 回调方法触发的时候。inteval自身正在运行(这里应该是下在运行第二个interval没有结束)。这里给我们展示了一个重要的信息:

interval 不会去关心当前的线程如今运行什么,它们会把自己的回调方法增加到队列中在不论什么情况下,即使它会让两个间隔的回调方法之间的时间降低。

最后,在第二个interval(图中应该是第三个,这里应为中间有一个被drop掉了)被 运行完之后,javasript引擎中已经没有东西能够用来运行了。

这也就是说。浏览器如今正在等一个新的异步事件须要去触发(occur)。在第50毫秒的时候,再一次触发了inteval回调。

这个时候。已经没有东西去堵塞它的运行。所以它增加到队列中之后就立马运行了。

接下来,让我们看一个样例更好的理解setTimeout与setInterval的差别:

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

这两段代码可能在功能的实现上很的相似。不经意一看,他们是全然一样的。

尤其是这个setTimeout代码会在上一个回调函数运行之后至少隔10毫秒再运行一次回调方法(它可能会超过10毫秒,但不会少于10毫秒)。可是setInteval 却会尝试10毫秒就运行一个回调函数,不会去管上一个回调是什么时候运行的。

These two pieces of code may appear to be functionally equivalent, at first glance, but they are not. Notably the setTimeout code will always have at least a 10ms delay after the previous callback execution (it may end up being more, but never less) whereas
the setInterval will attempt to execute a callback every 10ms regardless of when the last callback was executed.

这里有一些东西是我们从这里学到的,做一个总结:

1 javascript引擎只唯独一个单线程,正在运行的异步事件会增加到队列等待。

2 setTimeout与setInterval 是运行异步回调方法从根本上不一样的。

3 假设一个须要马上运行的定时器被堵塞了。它将被延迟运行。知道下一次线程空暇(那么被延迟的时间会超过定时器定义的时间)

4 interval 可能会没有延迟的连续运行回调方法,假设主线程了运行一个足够长的代码(比定时的延迟长)

全部的这些都是很重要的知识对于了解javascript引擎是怎样工作的。特别是对于大数量的回调事件发生的时候,为我们建立更好的应用代码建立好的基础。

----------------------------------------------------------------------------------------------------

原文出自jQuery的作者John Resig。

地址:http://ejohn.org/blog/how-javascript-timers-work/#postcomment

[ Javascript ] JavaScript中的定时器(Timer) 是怎样工作的!的更多相关文章

  1. python中实现定时器Timer

    实现定时器最简单的办法是就是循环中间嵌time.sleep(seconds), 这里我就不赘述了 # encoding: UTF-8 import threading #Timer(定时器)是Thre ...

  2. Python--day41--threading中的定时器Timer

    定时器Timer:定时开启线程 代码示例: #定时开启线程 import time from threading import Timer def func(): print('时间同步') #1-3 ...

  3. Java中的定时器Timer

    java.util.Timer是一个实用工具类,该类用来调度一个线程,使线程可以在将来某一时刻开始执行. Java的Timer类可以调度一个线程运行一次,或定期运行. java.util.TimerT ...

  4. 线程中的定时器Timer类

    Timer 定时器 几分钟之后执行一个任务. 创建了一个定时器相当于开启了一条线程,TimerTask相当于一个线程的任务.内部使用wait/notify机制来实现的. 用法非常的简单  就足以里面的 ...

  5. Swoole 中毫秒定时器(Timer)的使用

    间隔定时器, tick 定时器会持续触发,直到调用 clear() 清除为止. $timer = Swoole\Timer::tick(3000, function (int $timer_id, $ ...

  6. javascript中的定时器

    本文地址:[http://www.xiabingbao.com/javascript/2015/04/20/javascript-timer/] 在以前的文章[javascript中的定时器]中,简单 ...

  7. 浅谈JavaScript中的定时器

    引言 使用setTimeout()和setInterval()创建的定时器可以实现很多有意思的功能.很多人认为定时器是一个单独的线程(之前我也是),但是JavaScript是运行在单线程环境中的,而定 ...

  8. 【JavaScript】JavaScript中的Timer是怎么工作的( setTimeout,setInterval)

    原文(http://www.yeeyan.org/articles/view/luosheng/24380) 作为入门者来说,了解JavaScript中timer的工作方式是很重要的.通常它们的表现行 ...

  9. 前端笔记之JavaScript(九)定时器&JSON&同步异步/回调函数&函数节流&call/apply

    一.快捷位置和尺寸属性 DOM已经提供给我们计算后的样式,但是还是觉得不方便,因为计算后的样式属性值都是字符串类型. 不能直接参与运算. 所以DOM又提供了一些API:得到的就是number类型的数据 ...

随机推荐

  1. vs2015发布项目到虚拟主机组策略阻止csc.exe程序问题

    这个问题之前碰到过一次,这次又碰到,就记录一下解决方法. 这个问题的产生的原因,据说是虚拟主机没有权限执行exe文件造成的,如果是独立服务器的话发布就不会出现这个问题. 使用VS2015发布web项目 ...

  2. BZOJ 3223 Splay区间翻转

    思路: 区间翻转的裸题 终于tm理解splay了-- //By SiriusRen #include <cstdio> #include <cstring> #include ...

  3. android之软件键盘

    不弹出软件键盘 <activity android:name="PresCompleteActivity"              android:windowSoftIn ...

  4. jsp登录会话

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  5. 日志文件支持unicode字符的做法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 开发的程序兼容多字节字符集和unicode字符集,最近发现一个问题,在unicode字符集下输出的日志文件是乱码的.显 ...

  6. java 通过httpclient调用https 的webapi

    java如何通过httpclient 调用采用https方式的webapi?如何验证证书.示例:https://devdata.osisoft.com/p...需要通过httpclient调用该接口, ...

  7. javascript 优秀写法

    http://www.csdn.net/article/2014-01-06/2818025-Useful-JavaScript-Tips-Best-Practices

  8. Zero-input latency scheduler: Scheduler Overhaul

    Scheduler Overhaul, with contributions from rbyers, sadrul, rjkroege, sievers, epenner, skyostil, br ...

  9. jumpserver 新建用户收不到邮件

    在设置邮件开启pop3/smtp/imap 时 会提示要设置授权码 重启jumpserver 遇到错误  163 邮箱没有收到密码 点击更新没有效果 测试连接成功以后 ,删除用户 ,然后 重新 创建一 ...

  10. 【Codeforces Round #420 (Div. 2) C】Okabe and Boxes

    [题目链接]:http://codeforces.com/contest/821/problem/C [题意] 给你2*n个操作; 包括把1..n中的某一个数压入栈顶,以及把栈顶元素弹出; 保证压入和 ...