this repo has no description
at main 74 lines 2.4 kB view raw
1/** 2 * @name RequestAnimationFrameLimiter 3 * @description 4 * allows for multiple callbacks to be called 5 * within a single RAF function. 6 * It also spreads long running tasks across multiple 7 * microtask to help keep the main thread free for user interactions 8 * 9 */ 10export class RequestAnimationFrameLimiter { 11 private queue: Array<(timestamp?: number) => void>; 12 private RAF_FN_LIMIT_MS: number; 13 private requestId: number | null; 14 constructor() { 15 this.queue = []; 16 // ideal limit for scroll based animations: https://developers.google.com/web/fundamentals/performance/rendering/optimize-javascript-execution#reduce_complexity_or_use_web_workers 17 this.RAF_FN_LIMIT_MS = 3; 18 this.requestId = null; 19 } 20 21 private flush(): void { 22 this.requestId = 23 this.queue.length === 0 24 ? null 25 : window.requestAnimationFrame((timestamp) => { 26 const start = window.performance.now(); 27 let ellapsedTime = 0; 28 const { RAF_FN_LIMIT_MS } = this; 29 let count = 0; 30 31 while ( 32 count < this.queue.length && 33 ellapsedTime < RAF_FN_LIMIT_MS 34 ) { 35 let item = this.queue[count]; 36 if (item) { 37 item(timestamp); 38 } 39 const finishTime = window.performance.now(); 40 41 count = count + 1; 42 ellapsedTime = finishTime - start; 43 } 44 const newQueue = this.queue.slice(count); 45 46 this.queue = newQueue; 47 this.flush(); 48 }); 49 } 50 public add(callback: () => void): void { 51 this.queue.push(callback); 52 if (this.requestId === null) { 53 this.flush(); 54 } 55 } 56} 57 58let raf: RequestAnimationFrameLimiter | ServerSafeRAFLimiter = null; 59 60type ServerSafeRAFLimiter = { 61 add: (callback: () => void) => void; 62}; 63 64export const getRafQueue = () => { 65 if (typeof window === 'undefined') { 66 // SSR safe 67 raf = { 68 add: (callback: () => void) => callback(), 69 }; 70 } else if (raf === null) { 71 raf = new RequestAnimationFrameLimiter(); 72 } 73 return raf; 74};