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. 一劳永逸部署项目:通过tomcat加载环境变量

    一劳永逸部署项目:通过tomcat加载环境变量 转载自:https://blog.csdn.net/u010414666/article/details/46499953 一.说明 项目中经常会用到x ...

  2. UVa 1642 - Magical GCD(数论)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  3. python基础整理1

    基础知识 名字与对象,类与类型 变量:在Python中,存储一个数据,需要一个叫做变量的东西   num2 = 87 #num2是一个变量 变量的类型: 程序中为了更充分的利用内存空间以及更有效率的管 ...

  4. Docker实战(五)之端口映射与容器互联

    除了网络访问外,Docker还提供了两个很方便的功能来满足服务访问的基本需求:一个是允许映射容器内应用的服务端口到本地宿主主机;另一个是互联机制实现多个容器间通过容器名来快速访问. 1.端口映射实现访 ...

  5. Win32 HTTP Download

    头文件HTTPClient.h: #pragma once #ifndef HTTPClient_H_ #define HTTPClient_H_ #include <string> us ...

  6. 数字电路中应避免产生不必要的锁存器 Latch

    锁存器(Latch)是数字逻辑电路中很重要的一种基本电路,常见的锁存器包括三个端口:数据输入口.数据输出口.使能端.当使能端为高电平时,输入口的数据直接送到输出口,此时输入输出口可以看成是直接连通的: ...

  7. java 接口的概念

    一:概念 接口是功能的集合.同样可以看做一种数据类型,是比抽象类更为抽象的“类”. 接口描述应该具备的方法,并没有具体的实现.具体实现由接口的实现类(相当于接口的子类来完成). 好处: 使功能和实现分 ...

  8. HDU 1171 (01背包问题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1171 分析: 例如数据 3 10    2 20    1 30    1 获得这样一个降序的数组: ...

  9. 网络编程中的read,write函数

    关于TCP/IP协议,建议参考Richard Stevens的<TCP/IP Illustrated,vol1>(TCP/IP详解卷1). 关于第二层面,依然建议Richard Steve ...

  10. 解决Xcode 7 http无法使用的问题

    在info.plist文件中添加 <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbit ...