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. python SQLAlchemy复习

    下面的代码主要使用SQLAlchemy的ORM思想实现查询单词的功能: 实现输入一个单词,查询出与输入单词接近的单词以及单词的意思. 主要有以下三步: 1.创建数据表 2.插入数据 3.查询数据 1. ...

  2. 代码覆盖率测试及 GitHub 自动化集成

    本文对应项目为 learn-coverage-test,可以对照项目案例进行阅读. 覆盖率测试 在写代码的时候,我们有时候会进行代码测试以保证我们代码的可执行性.但是测试代码只能保证测试案例能够通过, ...

  3. javascript:typeof与instanceof区别

    from:http://www.wxwdesign.cn/article/skills/javascript_typeof_instanceof.htm JavaScript中typeof和insta ...

  4. 微信小程序 置顶/取消置顶

    wxml <view wx:for="{{confirmlist}}" wx:for-item="confirm" wx:for-index=" ...

  5. 4、JVM-虚拟机性能监控与故障处理工具

    前言: Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. 4.1.概述 给一个系统定位问题的时候,知识.经验是关键基础,数据是依据,工具是 ...

  6. PAT乙级1036

    1036 跟奥巴马一起编程 (15 分)   美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014 年底,为庆祝“计算机科学教育周”正式启动, ...

  7. html5复习--canvas

    一.简介 <canvas>是html5新增的标签,可以使用脚本(通常为JavaScript)在其中绘制图像的 HTML 元素.它可以用来制作照片集或者制作简单(也不是那么简单)的动画,甚至 ...

  8. spring cloud gateway之filter篇

    转载请标明出处: https://www.fangzhipeng.com 本文出自方志朋的博客 在上一篇文章详细的介绍了Gateway的Predict,Predict决定了请求由哪一个路由处理,在路由 ...

  9. CTF-Bugku-分析-信息提取

    CTF-Bugku-分析-信息提取 最近刷题的时候看到了这道比较有趣的题.而且网上也没找到wp,所以分享一下我的思路. 信息提取: 题目链接:http://ctf.bugku.com/challeng ...

  10. JavaWeb基础—会话管理之Cookie

    一.什么是会话 打开浏览器,浏览各种资源,点击各种超链接,直至关闭浏览器,整个过程称为会话 二.会话管理的两种技术 1.Cookie 基于客户端.在客户端记录信息来确认用户身份.以cookie的形式写 ...