class Ticker { static _ticker: Ticker = new Ticker(); private _isPause: boolean = false;//暂停中 _running: boolean = false; // 正在运行 _systemTime: number = 0; // 系统时间 _lastTime: number = 0; // 上次执行时间 _timerId; // 计时器id _delay: number = 10; // 延时设定 // _funcs: Array = []; // 钩子函数队列 _tickFuncs: Array = []; // 钩子函数队列//: {} Function _executeFuncs: Array = []; // 定时执行函数队列,按执行时间升序排序 /**暂停期间的时间 */ private _pauseTime: number = 0; /**暂停开始时间 */ private _pauseStartTime; constructor() { // console.error(" constructor _ticker "); } /** * 查找第一个大于目标值的值的下标 * @param time */ _searchIndex(time: number) { let funcs: Array = this._executeFuncs; let low: number = 0; let high: number = funcs.length; let mid: number = 0; while (low < high) { mid = Math.floor(low + (high - low) / 2); if (time >= funcs[mid].time) { low = mid + 1; } else { high = mid - 1; } } return low; } /** * 注册钩子函数(每次tick执行) * @param func 执行函数 */ _register(func: Function, caller):string { for (let i = 0; i < this._tickFuncs.length; i++) { const element = this._tickFuncs[i]; if (element.caller == caller && element.func == func) { console.error("重复的tick监听"); return element.id; } } let id = Util.GetUUID(6); let value: ExecuteTick = { func: func, caller: caller, id: id }; this._tickFuncs.push(value); return id; // if (!this._tickFuncs[caller]) { // this._tickFuncs[caller] = []; // } // let arr = this._tickFuncs[caller]; // if (arr.indexOf(func)) { // console.error("重复监听:" + caller + " " + func); // return; // } // this._tickFuncs[caller].push(func); // if (this._tickFuncs.indexOf(func) > -1) { // return; // } // this._tickFuncs.push(func); } /** * 注册一个函数,在一段时间之后执行 * @param func 执行函数 * @param delay 延时 * @param time 执行时系统时间 * @param loop 循环次数 */ _registerDelay(func: Function, delay: number, time: number, loop: number, id: string, count: number) { //判断是否已经注册过 // 先查找后插入 let index: number = this._searchIndex(time); let value: ExecuteValue = { func: func, time: time, delay: delay, loop: loop, id: id, count: count }; this._executeFuncs.splice(index, 0, value); } /** * 注册一个函数,在某个时间点执行 * @param func 执行函数 * @param time 执行时间 */ _registerTimer(func: Function, time: number) { // 先查找后插入 let index: number = this._searchIndex(time); let id = Util.GetUUID(6); let value: ExecuteValue = { func: func, time: time, id: id, count: 0 }; this._executeFuncs.splice(index, 0, value); return id; } /** * 移除tick函数 * @param func 执行函数 */ _unregister(func: Function,caller) { this._tickFuncs.map((value: ExecuteTick, index: number) => { if (value.caller==caller && func === value.func) { this._tickFuncs.splice(index, 1); } }); // for (let i = 0; i < this._tickFuncs.length; i++) { // const element = this._tickFuncs[i]; // if (element.caller == caller && element.func == func) { // console.error("重复的tick监听"); // return element.id; // } // } } /** * 移除tick函数 * @param func 执行函数 */ _unregisterById(id) { this._tickFuncs.map((value: ExecuteTick, index: number) => { if (value.id == id) { this._tickFuncs.splice(index, 1); } }); } // /** // * 移除钩子函数 // * @param func 执行函数 // */ // _unregisterDelay (func: Function) { // this._executeFuncs.map((value: ExecuteValue, index: number) => { // if (func === value.func) { // this._executeFuncs.splice(index, 1); // } // }); // } /** * 移除钩子函数 * @param func 执行函数 */ _unregisterDelay(id: string) { if (id) { this._executeFuncs.map((value: ExecuteValue, index: number) => { if (id === value.id) { this._executeFuncs.splice(index, 1); } }); } } _unregisterAll() { // this._funcs.map((value: Function, index: number) => { // this._funcs.splice(index, 1); // }); this._tickFuncs = []; this._executeFuncs = []; // if (this._timerId) { // clearTimeout(this._timerId); // this._timerId = null; // } this._stop(); } /** * 启动Ticker,并设置当前系统时间,通常与服务器时间同步 * @param systemTime 系统时间 */ _start(systemTime: number = 0) { if (this._running) { return; } // console.error("ticker start"); this._isPause = false; this._running = true; this._systemTime = systemTime; this._lastTime = new Date().getTime(); this._pauseTime = 0; this._update(); } /** * 链式执行定时器,钩子函数队列为每次调用必执行,定时执行函数队列为系统时间大于执行时间时调用并移出队列 */ _update() { if (!this._running) { return; } let currentTime: number = new Date().getTime(); if (this._pauseTime) { currentTime -= this._pauseTime; // this._pauseTime = undefined; } let delay: number = currentTime - this._lastTime; this._systemTime += delay; // tick函数队列,依次执行即可 this._tickFuncs.forEach((value: ExecuteTick) => { // value(delay); value.func.call(value.caller, delay*0.001); }); this._executeFunc(); this._lastTime = currentTime; this._timerId = setTimeout(this._update.bind(this), this._delay); // console.log("tick"); } /** * 执行定时函数 */ _executeFunc() { // 取数组首项进行时间校验 if (this._executeFuncs[0] && this._executeFuncs[0].time < this._systemTime) { // 取出数组首项并执行 let value: ExecuteValue = this._executeFuncs.shift(); value.func(++value.count); // 递归执行下一项 this._executeFunc(); // 判断重复执行次数 if (value.hasOwnProperty('loop')) { if (value.loop > 0 && --value.loop === 0) { return; } // 计算下次执行时间,插入队列 let fixTime: number =this._systemTime+value.delay;// value.time + value.delay; this._registerDelay(value.func, value.delay, fixTime, value.loop, value.id, value.count); } } } /** * 停止Ticker */ _stop() { if (this._timerId) { // console.error("clearTimeout:"+this._timerId); clearTimeout(this._timerId); this._timerId = null; } this._running = false; } _pause() { if (!this._running) { return; } this._isPause = true; this._running = false; this._pauseStartTime = new Date().getTime(); } _repause() { if (this._running) { return; } this._isPause = false; this._running = true; this._pauseTime += new Date().getTime() - this._pauseStartTime; this._update(); } private _registerCount(call, count): number { let me = this; let realCount = 0 let t = function () { if (me._isPause) { return; } realCount++; call(realCount); if (realCount >= count) { clearInterval(tid); } } let tid = setInterval(t, 1000) return tid; } private _unregistCount(id) { clearInterval(id); } /** * 公开的钩子函数注册方法 * @param func 执行函数 * @param func 调用者 */ static register(func: Function, caller): string { return this._ticker._register(func, caller); } /** * 公开的钩子函数移除方法 * @param func 执行函数 */ static unregister(func: Function, caller) { this._ticker._unregister(func, caller); } /** * 公开的钩子函数移除方法 * @param func 执行函数 */ static unregisterById(id: string) { this._ticker._unregisterById(id); } // /** // * 公开的钩子函数移除方法 // * @param func 执行函数 // */ // static unregisterDelay (func: Function) { // this._ticker._unregisterDelay(func); // } /** * 公开的钩子函数移除方法 * @param func 执行函数 */ static unregisterDelay(id: string) { this._ticker._unregisterDelay(id); } static unregisterAll() { this._ticker._unregisterAll(); } /** * 公开的延时执行函数方法,用户可设置执行次数,loop为0时无限循环 * @param func 执行函数 * @param delay 延时毫秒 * @param loop 循环次数 */ static registerDelay(func: Function, delay: number, loop: number = 1): string { let time: number = this._ticker._systemTime + delay; let id = Util.GetUUID(6); this._ticker._registerDelay(func, delay, time, loop, id, 0); return id } /** * 公开的定时执行函数方法 * @param func 执行函数 * @param time 执行时间 */ static registerTimer(func: Function, time: number) { this._ticker._registerTimer(func, time); } public static registerCount(call, count): number { return this._ticker._registerCount(call,count); } public static unregistCount(id) { this._ticker._unregistCount(id); } /** * 公开的启动方法 * @param systemTime 系统时间如:new Date().getTime() */ static start(systemTime: number = 0) { // console.log("Tick->start:"+DateTime.formatDate()); this._ticker._start(systemTime); } /** * 公开的停止方法:只是暂停调用。重新开始后,会全部调用停用的次数。 * 需要移除所有监听,使用:unregisterAll */ static stop() { // console.log("Tick->stop:"+DateTime.formatDate()); this._ticker._stop(); } static pause() { this._ticker._pause(); } static resume() { this._ticker._repause(); } static tooglePause() { if (this._ticker._isPause) { this.resume(); } else { this.pause(); } } static get isPause(): boolean { return this._ticker._isPause; } /** * 系统时间 */ static get systemTime(): number { return this._ticker._systemTime; } /** * 正在运行 */ static get running(): boolean { return this._ticker._running; } } interface ExecuteValue { id: string; func: Function; time: number; delay?: number; loop?: number; count: number; } interface ExecuteTick { id: string; func: Function; caller; // dt: number; // sumTime:number } (window).Ticker = Ticker;