Tick.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. class Ticker {
  2. static _ticker: Ticker = new Ticker();
  3. private _isPause: boolean = false;//暂停中
  4. _running: boolean = false; // 正在运行
  5. _systemTime: number = 0; // 系统时间
  6. _lastTime: number = 0; // 上次执行时间
  7. _timerId; // 计时器id
  8. _delay: number = 10; // 延时设定
  9. // _funcs: Array<Function> = []; // 钩子函数队列
  10. _tickFuncs: Array<ExecuteTick> = []; // 钩子函数队列//: {} Function
  11. _executeFuncs: Array<ExecuteValue> = []; // 定时执行函数队列,按执行时间升序排序
  12. /**暂停期间的时间 */
  13. private _pauseTime: number = 0;
  14. /**暂停开始时间 */
  15. private _pauseStartTime;
  16. constructor() {
  17. // console.error(" constructor _ticker ");
  18. }
  19. /**
  20. * 查找第一个大于目标值的值的下标
  21. * @param time
  22. */
  23. _searchIndex(time: number) {
  24. let funcs: Array<ExecuteValue> = this._executeFuncs;
  25. let low: number = 0;
  26. let high: number = funcs.length;
  27. let mid: number = 0;
  28. while (low < high) {
  29. mid = Math.floor(low + (high - low) / 2);
  30. if (time >= funcs[mid].time) {
  31. low = mid + 1;
  32. } else {
  33. high = mid - 1;
  34. }
  35. }
  36. return low;
  37. }
  38. /**
  39. * 注册钩子函数(每次tick执行)
  40. * @param func 执行函数
  41. */
  42. _register(func: Function, caller):string {
  43. for (let i = 0; i < this._tickFuncs.length; i++) {
  44. const element = this._tickFuncs[i];
  45. if (element.caller == caller && element.func == func) {
  46. console.error("重复的tick监听");
  47. return element.id;
  48. }
  49. }
  50. let id = Util.GetUUID(6);
  51. let value: ExecuteTick = { func: func, caller: caller, id: id };
  52. this._tickFuncs.push(value);
  53. return id;
  54. // if (!this._tickFuncs[caller]) {
  55. // this._tickFuncs[caller] = [];
  56. // }
  57. // let arr = this._tickFuncs[caller];
  58. // if (arr.indexOf(func)) {
  59. // console.error("重复监听:" + caller + " " + func);
  60. // return;
  61. // }
  62. // this._tickFuncs[caller].push(func);
  63. // if (this._tickFuncs.indexOf(func) > -1) {
  64. // return;
  65. // }
  66. // this._tickFuncs.push(func);
  67. }
  68. /**
  69. * 注册一个函数,在一段时间之后执行
  70. * @param func 执行函数
  71. * @param delay 延时
  72. * @param time 执行时系统时间
  73. * @param loop 循环次数
  74. */
  75. _registerDelay(func: Function, delay: number, time: number, loop: number, id: string, count: number) {
  76. //判断是否已经注册过
  77. // 先查找后插入
  78. let index: number = this._searchIndex(time);
  79. let value: ExecuteValue = { func: func, time: time, delay: delay, loop: loop, id: id, count: count };
  80. this._executeFuncs.splice(index, 0, value);
  81. }
  82. /**
  83. * 注册一个函数,在某个时间点执行
  84. * @param func 执行函数
  85. * @param time 执行时间
  86. */
  87. _registerTimer(func: Function, time: number) {
  88. // 先查找后插入
  89. let index: number = this._searchIndex(time);
  90. let id = Util.GetUUID(6);
  91. let value: ExecuteValue = { func: func, time: time, id: id, count: 0 };
  92. this._executeFuncs.splice(index, 0, value);
  93. return id;
  94. }
  95. /**
  96. * 移除tick函数
  97. * @param func 执行函数
  98. */
  99. _unregister(func: Function,caller) {
  100. this._tickFuncs.map((value: ExecuteTick, index: number) => {
  101. if (value.caller==caller && func === value.func) {
  102. this._tickFuncs.splice(index, 1);
  103. }
  104. });
  105. // for (let i = 0; i < this._tickFuncs.length; i++) {
  106. // const element = this._tickFuncs[i];
  107. // if (element.caller == caller && element.func == func) {
  108. // console.error("重复的tick监听");
  109. // return element.id;
  110. // }
  111. // }
  112. }
  113. /**
  114. * 移除tick函数
  115. * @param func 执行函数
  116. */
  117. _unregisterById(id) {
  118. this._tickFuncs.map((value: ExecuteTick, index: number) => {
  119. if (value.id == id) {
  120. this._tickFuncs.splice(index, 1);
  121. }
  122. });
  123. }
  124. // /**
  125. // * 移除钩子函数
  126. // * @param func 执行函数
  127. // */
  128. // _unregisterDelay (func: Function) {
  129. // this._executeFuncs.map((value: ExecuteValue, index: number) => {
  130. // if (func === value.func) {
  131. // this._executeFuncs.splice(index, 1);
  132. // }
  133. // });
  134. // }
  135. /**
  136. * 移除钩子函数
  137. * @param func 执行函数
  138. */
  139. _unregisterDelay(id: string) {
  140. if (id) {
  141. this._executeFuncs.map((value: ExecuteValue, index: number) => {
  142. if (id === value.id) {
  143. this._executeFuncs.splice(index, 1);
  144. }
  145. });
  146. }
  147. }
  148. _unregisterAll() {
  149. // this._funcs.map((value: Function, index: number) => {
  150. // this._funcs.splice(index, 1);
  151. // });
  152. this._tickFuncs = [];
  153. this._executeFuncs = [];
  154. // if (this._timerId) {
  155. // clearTimeout(this._timerId);
  156. // this._timerId = null;
  157. // }
  158. this._stop();
  159. }
  160. /**
  161. * 启动Ticker,并设置当前系统时间,通常与服务器时间同步
  162. * @param systemTime 系统时间
  163. */
  164. _start(systemTime: number = 0) {
  165. if (this._running) {
  166. return;
  167. }
  168. // console.error("ticker start");
  169. this._isPause = false;
  170. this._running = true;
  171. this._systemTime = systemTime;
  172. this._lastTime = new Date().getTime();
  173. this._pauseTime = 0;
  174. this._update();
  175. }
  176. /**
  177. * 链式执行定时器,钩子函数队列为每次调用必执行,定时执行函数队列为系统时间大于执行时间时调用并移出队列
  178. */
  179. _update() {
  180. if (!this._running) {
  181. return;
  182. }
  183. let currentTime: number = new Date().getTime();
  184. if (this._pauseTime) {
  185. currentTime -= this._pauseTime;
  186. // this._pauseTime = undefined;
  187. }
  188. let delay: number = currentTime - this._lastTime;
  189. this._systemTime += delay;
  190. // tick函数队列,依次执行即可
  191. this._tickFuncs.forEach((value: ExecuteTick) => {
  192. // value(delay);
  193. value.func.call(value.caller, delay*0.001);
  194. });
  195. this._executeFunc();
  196. this._lastTime = currentTime;
  197. this._timerId = setTimeout(this._update.bind(this), this._delay);
  198. // console.log("tick");
  199. }
  200. /**
  201. * 执行定时函数
  202. */
  203. _executeFunc() {
  204. // 取数组首项进行时间校验
  205. if (this._executeFuncs[0] && this._executeFuncs[0].time < this._systemTime) {
  206. // 取出数组首项并执行
  207. let value: ExecuteValue = this._executeFuncs.shift();
  208. value.func(++value.count);
  209. // 递归执行下一项
  210. this._executeFunc();
  211. // 判断重复执行次数
  212. if (value.hasOwnProperty('loop')) {
  213. if (value.loop > 0 && --value.loop === 0) {
  214. return;
  215. }
  216. // 计算下次执行时间,插入队列
  217. let fixTime: number =this._systemTime+value.delay;// value.time + value.delay;
  218. this._registerDelay(value.func, value.delay, fixTime, value.loop, value.id, value.count);
  219. }
  220. }
  221. }
  222. /**
  223. * 停止Ticker
  224. */
  225. _stop() {
  226. if (this._timerId) {
  227. // console.error("clearTimeout:"+this._timerId);
  228. clearTimeout(this._timerId);
  229. this._timerId = null;
  230. }
  231. this._running = false;
  232. }
  233. _pause() {
  234. if (!this._running) { return; }
  235. this._isPause = true;
  236. this._running = false;
  237. this._pauseStartTime = new Date().getTime();
  238. }
  239. _repause() {
  240. if (this._running) { return; }
  241. this._isPause = false;
  242. this._running = true;
  243. this._pauseTime += new Date().getTime() - this._pauseStartTime;
  244. this._update();
  245. }
  246. private _registerCount(call, count): number {
  247. let me = this;
  248. let realCount = 0
  249. let t = function () {
  250. if (me._isPause) { return; }
  251. realCount++;
  252. call(realCount);
  253. if (realCount >= count) {
  254. clearInterval(tid);
  255. }
  256. }
  257. let tid = setInterval(t, 1000)
  258. return tid;
  259. }
  260. private _unregistCount(id) {
  261. clearInterval(id);
  262. }
  263. /**
  264. * 公开的钩子函数注册方法
  265. * @param func 执行函数
  266. * @param func 调用者
  267. */
  268. static register(func: Function, caller): string {
  269. return this._ticker._register(func, caller);
  270. }
  271. /**
  272. * 公开的钩子函数移除方法
  273. * @param func 执行函数
  274. */
  275. static unregister(func: Function, caller) {
  276. this._ticker._unregister(func, caller);
  277. }
  278. /**
  279. * 公开的钩子函数移除方法
  280. * @param func 执行函数
  281. */
  282. static unregisterById(id: string) {
  283. this._ticker._unregisterById(id);
  284. }
  285. // /**
  286. // * 公开的钩子函数移除方法
  287. // * @param func 执行函数
  288. // */
  289. // static unregisterDelay (func: Function) {
  290. // this._ticker._unregisterDelay(func);
  291. // }
  292. /**
  293. * 公开的钩子函数移除方法
  294. * @param func 执行函数
  295. */
  296. static unregisterDelay(id: string) {
  297. this._ticker._unregisterDelay(id);
  298. }
  299. static unregisterAll() {
  300. this._ticker._unregisterAll();
  301. }
  302. /**
  303. * 公开的延时执行函数方法,用户可设置执行次数,loop为0时无限循环
  304. * @param func 执行函数
  305. * @param delay 延时毫秒
  306. * @param loop 循环次数
  307. */
  308. static registerDelay(func: Function, delay: number, loop: number = 1): string {
  309. let time: number = this._ticker._systemTime + delay;
  310. let id = Util.GetUUID(6);
  311. this._ticker._registerDelay(func, delay, time, loop, id, 0);
  312. return id
  313. }
  314. /**
  315. * 公开的定时执行函数方法
  316. * @param func 执行函数
  317. * @param time 执行时间
  318. */
  319. static registerTimer(func: Function, time: number) {
  320. this._ticker._registerTimer(func, time);
  321. }
  322. public static registerCount(call, count): number {
  323. return this._ticker._registerCount(call,count);
  324. }
  325. public static unregistCount(id) {
  326. this._ticker._unregistCount(id);
  327. }
  328. /**
  329. * 公开的启动方法
  330. * @param systemTime 系统时间如:new Date().getTime()
  331. */
  332. static start(systemTime: number = 0) {
  333. // console.log("Tick->start:"+DateTime.formatDate());
  334. this._ticker._start(systemTime);
  335. }
  336. /**
  337. * 公开的停止方法:只是暂停调用。重新开始后,会全部调用停用的次数。
  338. * 需要移除所有监听,使用:unregisterAll
  339. */
  340. static stop() {
  341. // console.log("Tick->stop:"+DateTime.formatDate());
  342. this._ticker._stop();
  343. }
  344. static pause() {
  345. this._ticker._pause();
  346. }
  347. static resume() {
  348. this._ticker._repause();
  349. }
  350. static tooglePause() {
  351. if (this._ticker._isPause) {
  352. this.resume();
  353. } else {
  354. this.pause();
  355. }
  356. }
  357. static get isPause(): boolean {
  358. return this._ticker._isPause;
  359. }
  360. /**
  361. * 系统时间
  362. */
  363. static get systemTime(): number {
  364. return this._ticker._systemTime;
  365. }
  366. /**
  367. * 正在运行
  368. */
  369. static get running(): boolean {
  370. return this._ticker._running;
  371. }
  372. }
  373. interface ExecuteValue {
  374. id: string;
  375. func: Function;
  376. time: number;
  377. delay?: number;
  378. loop?: number;
  379. count: number;
  380. }
  381. interface ExecuteTick {
  382. id: string;
  383. func: Function;
  384. caller;
  385. // dt: number;
  386. // sumTime:number
  387. }
  388. (<any>window).Ticker = Ticker;