RafHelper.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. /**
  2. * This class implemented setTimeout and setInterval using RequestAnimationFrame
  3. */
  4. export default class RafHelper {
  5. readonly TIMEOUT = 'timeout';
  6. readonly INTERVAL = 'interval';
  7. private timeoutMap: any = {}; // timeout map, key is symbol
  8. private intervalMap: any = {}; // interval map
  9. private run(type = this.INTERVAL, cb: () => void, interval = 16.7) {
  10. const now = Date.now;
  11. let startTime = now();
  12. let endTime = startTime;
  13. const timerSymbol = Symbol('');
  14. const loop = () => {
  15. this.setIdMap(timerSymbol, type, loop);
  16. endTime = now();
  17. if (endTime - startTime >= interval) {
  18. if (type === this.intervalMap) {
  19. startTime = now();
  20. endTime = startTime;
  21. }
  22. cb();
  23. if (type === this.TIMEOUT) {
  24. this.clearTimeout(timerSymbol);
  25. }
  26. }
  27. };
  28. this.setIdMap(timerSymbol, type, loop);
  29. return timerSymbol;
  30. }
  31. private setIdMap(timerSymbol: symbol, type: string, loop: (time: number) => void) {
  32. const id = requestAnimationFrame(loop);
  33. if (type === this.INTERVAL) {
  34. this.intervalMap[timerSymbol] = id;
  35. } else if (type === this.TIMEOUT) {
  36. this.timeoutMap[timerSymbol] = id;
  37. }
  38. }
  39. public setTimeout(cb: () => void, interval: number) {
  40. return this.run(this.TIMEOUT, cb, interval);
  41. }
  42. public clearTimeout(timer: symbol) {
  43. cancelAnimationFrame(this.timeoutMap[timer]);
  44. }
  45. public setInterval(cb: () => void, interval: number) {
  46. return this.run(this.INTERVAL, cb, interval);
  47. }
  48. public clearInterval(timer: symbol) {
  49. cancelAnimationFrame(this.intervalMap[timer]);
  50. }
  51. }