Laya1.x Timer小记
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小记的更多相关文章
- Atitit.spring体系结构大总结
Atitit.spring体系结构大总结 1. Srping mvc 1 2. Ioc 4 3. ApplicationContext在BeanFactory的基础上构建,区别 4 4. Aop 5 ...
- ConCurrent in Practice小记 (3)
ConCurrent in Practice小记 (3) 高级同步技巧 Semaphore Semaphore信号量,据说是Dijkstra大神发明的.内部维护一个许可集(Permits Set),用 ...
- [原]Paste.deploy 与 WSGI, keystone 小记
Paste.deploy 与 WSGI, keystone 小记 名词解释: Paste.deploy 是一个WSGI工具包,用于更方便的管理WSGI应用, 可以通过配置文件,将WSGI应用加载起来. ...
- C# - 计时器Timer
System.Timers.Timer 服务器计时器,允许指定在应用程序中引发事件的重复时间间隔. using System.Timers: // 在应用程序中生成定期事件 public class ...
- winform 用户控件、 动态创建添加控件、timer控件、控件联动
用户控件: 相当于自定义的一个panel 里面可以放各种其他控件,并可以在后台一下调用整个此自定义控件. 使用方法:在项目上右键.添加.用户控件,之后用户控件的编辑与普通容器控件类似.如果要在后台往窗 ...
- 【WPF】 Timer与 dispatcherTimer 在wpf中你应该用哪个?
源:Roboby 1.timer或重复生成timer事件,dispatchertimer是集成到队列中的一个时钟.2.dispatchertimer更适合在wpf中访问UI线程上的元素 3.Dispa ...
- MySql 小记
MySql 简单 小记 以备查看 1.sql概述 1.什么是sql? 2.sql发展过程? 3.sql标准与方言的关系? 4.常用数据库? 5.MySql数据库安装? 2.关键概念 表结构----- ...
- STM32F10xxx 之 System tick Timer(SYSTICK Timer)
背景 研究STM32F10xxx定时器的时候,无意间看到了System tick Timer,于是比较深入的了解下,在此做个记录. 正文 System tick Timer是Cotex-M内核的24位 ...
- 本地数据Store。Cookie,Session,Cache的理解。Timer类主要用于定时性、周期性任务 的触发。刷新Store,Panel
本地数据Store var monthStore = Ext.create('Ext.data.Store', { storeId : 'monthStore', autoLoad : false, ...
随机推荐
- Redis info参数总结
可以看到,info的输出结果是分几块的,有Servers.Clients.Memory等等,通过info后面接这些参数,可以指定输出某一块数据. 下面是针对info的输出在旁边注释了,因为对Redis ...
- Java虚拟机17:互斥同步、锁优化及synchronized和volatile
互斥同步 互斥同步(Mutual Exclusion & Synchronization)是常见的一种并发正确性保证手段.同步是指子啊多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一 ...
- Objective-C 与命名空间
http://blog.csdn.net/michelle__/article/details/52528172 Objective-C 在Objective-C应用中的所有类名都必须是全局唯一的.命 ...
- cocos2d-x3.0 柱图
画柱图就是多画几个矩形之后放在一起,这个实现了基本功能还不够完好假设要用到项目中须要自己改动. 原文地址:http://blog.csdn.net/qqmcy/article/details/2598 ...
- Linux环境变量配置文件/etc/profile、/etc/bashrc、~/.bashrc的区别以及一些隐藏文件的作用
①/etc/profile: 该文件登录操作系统时,为每个用户设置环境信息,当用户第一次登录时,该文件被执行.也就是说这个文件对每个shell都有效,用于获取系统的环境信息. ②/etc/bashrc ...
- 如何搭建github+hexo博客-转
1.前言 其实早在这之前我就一直想过写博客,但由于种种原因一直没有去学习这方面的知识,最近半个月(从开始动手到搭建好)一直陆陆续续的在着手这方面的工作.从开始到搭建完成的过程中遇到了很多困难,因为在这 ...
- Sql Server 数据库扩展
1. 查询一个表的所有列名 ------查询一个表的所有列名 Select Name FROM SysColumns Where id=Object_Id('Sys_User') select t.c ...
- 真机测试出现INSTALL_FAILED_USER_RESTRICTED安装错误
之前用小米测试的时候遇到一个问题,两个一样型号的手机一个能直接用Android Studio安装公司的项目一个却不可以,总是报INSTALL_FAILED_USER_RESTRICTED错误,具体见下 ...
- bapi获取物料的可用数量及MRP信息(MD04)
需求:在报表里面添加可用数量字段,数据来源于MD04. 使用到的bapi:MD_STOCK_REQUIREMENTS_LIST_API 这个bapi可以查看到MRP信息以及可用数量. bapi需要的参 ...
- HBase基础概念
定义 非关系型分布式列式数据库,支持大数据量查询(百万,上亿行) 概要 数据存储:HDFS 数据计算:MapReduce/Spark 服务协调:Zookeeper 特征 列式存储(列只有一种类型byt ...