Timer是时钟管理类,在Laya初始化的时候会创建一个实例,通过Laya.timer访问。

TimerHandler
  • TimerHandler是对每一个定时任务的封装,每次调用frameOnce、frameLoop、once、loop或者callLayer都会产生一个TimerHandler实例。
  • TimerHandler会缓存传入的参数(args),当定时器触发时,会将对应的args传递给对应回调。
public var key:int;   			//唯一key,用于快速找到对应handler
public var repeat:Boolean; //是否是重复调用 分别对应 once/loop
public var delay:int; //延时
public var userFrame:Boolean; // true表示使用帧计时 false表示使用时间计时
public var exeTime:int; //下次执行的时间
public var caller:* //调用者
public var method:Function; //调用方法
public var args:Array; //触发时的参数
public var jumpFrame:Boolean; //时钟是否跳帧。基于时间的循环回调,单位时间间隔内,如能执行多次回调,出于性能考虑,引擎默认只执行一次,设置jumpFrame=true后,则回调会连续执行多次 public function clear():void {
caller = null;
method = null;
args = null;
} public function run(withClear:Boolean):void {
var caller:* = this.caller;
/*[IF-FLASH]*/
if ((caller is Node) && caller.destroyed)
/*[IF-FLASH]*/
return clear();
//[IF-SCRIPT] if (caller && caller.destroyed) return clear();
var method:Function = this.method;
var args:Array = this.args;
withClear && clear();
if (method == null) return;
args ? method.apply(caller, args) : method.call(caller);
}
Timer数据类型定义
/**@private */
private static var _pool:Array = []; //TimerHandler池 /*[DISABLE-ADD-VARIABLE-DEFAULT-VALUE]*/
/** 两帧之间的时间间隔,单位毫秒。*/
private var _delta:int = 0;
/** 时针缩放。*/
public var scale:Number = 1;
/** 当前帧开始的时间。*/
public var currTimer:Number = _now();
/** 当前的帧数。*/
public var currFrame:int = 0;
/**@private */
private var _lastTimer:Number = _now(); //上一帧的时间
/**@private */
private var _mid:int = 1; //用于生成唯一key
/**@private */
/*[IF-FLASH]*/ //TimerHandler的map 用于查找Handler(包括Later的handler)
private var _map:flash.utils.Dictionary = new flash.utils.Dictionary(true);
//[IF-JS] private var _map:Array = [];
/**@private */
private var _laters:Array = []; //存放callLater创建的handler
/**@private */
private var _handlers:Array = []; //存放非callLater创建的handler,包括frameOnce、frameLoop、once、loop
/**@private */
private var _temp:Array = []; //临时数组,用于清理
/**@private */
private var _count:int = 0; //记录handler.method为空的数量,检测是否清理
初始化
/**@private */
protected function _init():void {
Laya.timer && Laya.timer.frameLoop(1, this, _update);
}

除了Laya.timer之外,其他的timer的实例都是注册到Laya.timer的frameLoop中。

_create方法
  • 创建对应的TimerHandler。
  • 如果coverBefore并且已经注册过相同Handler,则覆盖之前的handler
  • 设置对应参数,并计算下一次执行的时间。
  • 为Handler创建唯一key,添加到_map中,用于快速查找。
  • 将handler放到_handler数组中,用于_update时遍历。

frameOnce、frameLoop、once、loop实现上都是调用_create方法,传入对应的参数,将handler注册到timer中,等待_update执行相关计算。

/** @private */
public function _create(useFrame:Boolean, repeat:Boolean, delay:int, caller:*, method:Function, args:Array, coverBefore:Boolean):TimerHandler {
//如果延迟为0,则立即执行
if (!delay) {
method.apply(caller, args);
return null;
} //先覆盖相同函数的计时
if (coverBefore) {
var handler:TimerHandler = _getHandler(caller, method);
if (handler) {
handler.repeat = repeat;
handler.userFrame = useFrame;
handler.delay = delay;
handler.caller = caller;
handler.method = method;
handler.args = args;
handler.exeTime = delay + (useFrame ? this.currFrame : this.currTimer + _now() - _lastTimer);
return handler;
}
} //找到一个空闲的timerHandler
handler = _pool.length > 0 ? _pool.pop() : new TimerHandler();
handler.repeat = repeat;
handler.userFrame = useFrame;
handler.delay = delay;
handler.caller = caller;
handler.method = method;
handler.args = args;
handler.exeTime = delay + (useFrame ? this.currFrame : this.currTimer + _now() - _lastTimer) + 1; //索引handler
_indexHandler(handler); //插入数组
_handlers.push(handler); return handler;
}
callLater
  • callLater使用延时执行,再Timer.update执行末尾调用。
  • 如果对应的caller和method已经注册过,则不会重复注册。
  • 创建的TimerHandler会放到_laters数组中。
_update
  • 计算当前帧和当前时间。
  • 计算delta。
  • 遍历handler数组,检查时间/帧是否超过了handler的exeTime。
  • 超过时间handler执行回调,如果是once则将handler的caller和method设置为空;如果是loop则执行回调,并计算下次执行的时间。如果下次调用的时间间隔内,可以触发多次回调,默认情况下执行执行一次回调。如果设置为jumpFrame则会调用多次回调(如delay为1毫秒,delta为30毫秒,则下个update时,会调用30次回调)。
  • 遍历数组时,会记录method为空的handler的数量,当数量为30或者200帧时,会清理一次没用的handler,将没用的handler回收到池中。
  • 执行完所有handler之后,遍历所有laters数组,执行callLater所注册的回调。执行完成后,清理所有laters数组。
/**
* @private
* 帧循环处理函数。
*/
public function _update():void {
if (scale <= 0) {
_lastTimer =_now();
return;
}
var frame:int = this.currFrame = this.currFrame + scale;
var now:Number = _now();
_delta = (now - _lastTimer) * scale;
var timer:Number = this.currTimer = this.currTimer + _delta;
_lastTimer = now; //处理handler
var handlers:Array = this._handlers;
_count = 0;
for (i = 0, n = handlers.length; i < n; i++) {
handler = handlers[i];
if (handler.method !== null) {
var t:int = handler.userFrame ? frame : timer;
if (t >= handler.exeTime) {
if (handler.repeat) {
if (!handler.jumpFrame) {
handler.exeTime += handler.delay;
handler.run(false);
if (t > handler.exeTime) {
//如果执行一次后还能再执行,做跳出处理,如果想用多次执行,需要设置jumpFrame=true
handler.exeTime += Math.ceil((t - handler.exeTime) / handler.delay) * handler.delay;
}
} else {
while (t >= handler.exeTime) {
handler.exeTime += handler.delay;
handler.run(false);
}
}
} else {
handler.run(true);
}
}
} else {
_count++;
}
} if (_count > 30 || frame % 200 === 0) _clearHandlers(); //处理callLater
var laters:Array = this._laters;
for (var i:int = 0, n:int = laters.length - 1; i <= n; i++) {
var handler:TimerHandler = laters[i];
if (handler.method !== null) {
/*[IF-FLASH]*/
_map[handler.method] = null;
//[IF-SCRIPT]_map[handler.key] = null;
handler.run(false);
}
_recoverHandler(handler);
i === n && (n = laters.length - 1);
}
laters.length = 0;
}
其他
  • Laya.timer._update是在Laya.stage.loop中调用,Laya.stage.loop是在Render中调用。

  • 在Frash中,监听enterFrame事件。

  • 在js中则是注册requestAnimationFrame,来进入渲染帧。

  • 当stage不可见时(如切到后台),则timer._update每一秒触发一次。一秒钟一帧,当切回前台后,帧率恢复正常。

  • update是在渲染之前执行。

  • Laya.stage控制实际帧率,根据Laya.stage.frameRate。

Laya1.x Timer小记的更多相关文章

  1. Atitit.spring体系结构大总结

    Atitit.spring体系结构大总结 1. Srping mvc 1 2. Ioc 4 3. ApplicationContext在BeanFactory的基础上构建,区别 4 4. Aop 5 ...

  2. ConCurrent in Practice小记 (3)

    ConCurrent in Practice小记 (3) 高级同步技巧 Semaphore Semaphore信号量,据说是Dijkstra大神发明的.内部维护一个许可集(Permits Set),用 ...

  3. [原]Paste.deploy 与 WSGI, keystone 小记

    Paste.deploy 与 WSGI, keystone 小记 名词解释: Paste.deploy 是一个WSGI工具包,用于更方便的管理WSGI应用, 可以通过配置文件,将WSGI应用加载起来. ...

  4. C# - 计时器Timer

    System.Timers.Timer 服务器计时器,允许指定在应用程序中引发事件的重复时间间隔. using System.Timers: // 在应用程序中生成定期事件 public class ...

  5. winform 用户控件、 动态创建添加控件、timer控件、控件联动

    用户控件: 相当于自定义的一个panel 里面可以放各种其他控件,并可以在后台一下调用整个此自定义控件. 使用方法:在项目上右键.添加.用户控件,之后用户控件的编辑与普通容器控件类似.如果要在后台往窗 ...

  6. 【WPF】 Timer与 dispatcherTimer 在wpf中你应该用哪个?

    源:Roboby 1.timer或重复生成timer事件,dispatchertimer是集成到队列中的一个时钟.2.dispatchertimer更适合在wpf中访问UI线程上的元素 3.Dispa ...

  7. MySql 小记

    MySql  简单 小记 以备查看 1.sql概述 1.什么是sql? 2.sql发展过程? 3.sql标准与方言的关系? 4.常用数据库? 5.MySql数据库安装? 2.关键概念 表结构----- ...

  8. STM32F10xxx 之 System tick Timer(SYSTICK Timer)

    背景 研究STM32F10xxx定时器的时候,无意间看到了System tick Timer,于是比较深入的了解下,在此做个记录. 正文 System tick Timer是Cotex-M内核的24位 ...

  9. 本地数据Store。Cookie,Session,Cache的理解。Timer类主要用于定时性、周期性任务 的触发。刷新Store,Panel

    本地数据Store var monthStore = Ext.create('Ext.data.Store', { storeId : 'monthStore', autoLoad : false, ...

随机推荐

  1. ubuntu 12.04 eclipse增加桌面快捷方式

    1.创建桌面启动器(编辑/usr/share/applications/eclipse.desktop) [Desktop Entry] Encoding=UTF-8 Name=eclipse Com ...

  2. python第十九课——random模块中的常用函数

    1.random():返回一个[0,1)的随机浮点数(双精度浮点数) 2.uniform(a,b): 返回[a,b]之间的一个随机浮点数(双精度浮点数) [注意]a和b接受的数据大小随意 例如:3.r ...

  3. python第七课——循环结构 while

    while循环: 2.1.有四要素组成: ①.初始化条件(执行一次)一个起始数据/起点,一般使用变量来进行存储 ②.循环条件(可能执行多次)循环合适结束全靠它,执行结果为True,那么循环继续,反之, ...

  4. 超链接<a>标签用法

    1.a标签点击事件 1>1a href="javascript:js_method();" 这是我们平台上常用的方法,但是这种方法在传递this等参数的时候很容易出问题,而且 ...

  5. js如何将时间戳转换为标准时间

    function formatDate(date,fmt){ let o = { 'M+' : date.getMonth() +1, //月份 'd+' : date.getDate(), //日 ...

  6. 新浪微博资深大牛全方位剖析 iOS 高级面试

    第1章 课程简介本章对这门课程所讲述内容进行概要介绍,其中包括课程目标.适合人群,课程特色.课程收获.课程安排等.整个课程学习完结后,有机会获得电话模拟面试及内推. 1-1 课前必读(不看会错过一个亿 ...

  7. 封装一个统一返回json结果类JsonResult

    import java.io.Serializable; public class JsonResult implements Serializable{ private static final l ...

  8. python apsheduler cron 参数解析

    from:https://apscheduler.readthedocs.io/en/v2.1.2/cronschedule.html Cron-style scheduling This is th ...

  9. Docker Cache mechanism

    Docker build 的 cache 机制: Docker Daemon 通过 Dockerfile 构建镜像时,当发现即将新构建出的镜像 与已有的新镜像重复时,可以选择放弃构建新的镜像,而是选用 ...

  10. 前端实现文件在线预览txt,pdf,doc,xls,ppt几种格式

    做法就是使用iframe标签 1.text,pdf的文件预览 <iframe class="filename" :src="文件的地址" width='1 ...