diff --git a/src/raf.ts b/src/raf.ts index 25c2dd3c..40e0ae6e 100644 --- a/src/raf.ts +++ b/src/raf.ts @@ -7,8 +7,42 @@ if (typeof window !== 'undefined' && 'requestAnimationFrame' in window) { caf = (handle: number) => window.cancelAnimationFrame(handle); } -export default function wrapperRaf(callback: () => void): number { - return raf(callback); +let rafUUID = 0; +const rafIds = new Map(); + +function cleanup(id: number) { + rafIds.delete(id); +} + +export default function wrapperRaf(callback: () => void, times = 1): number { + rafUUID += 1; + const id = rafUUID; + + function callRef(leftTimes: number) { + if (leftTimes === 0) { + // Clean up + cleanup(id); + + // Trigger + callback(); + } else { + // Next raf + const realId = raf(() => { + callRef(leftTimes - 1); + }); + + // Bind real raf id + rafIds.set(id, realId); + } + } + + callRef(times); + + return id; } -wrapperRaf.cancel = caf; +wrapperRaf.cancel = (id: number) => { + const realId = rafIds.get(id); + cleanup(realId); + return caf(realId); +}; diff --git a/tests/raf.test.js b/tests/raf.test.js index 374053e5..5a17076c 100644 --- a/tests/raf.test.js +++ b/tests/raf.test.js @@ -16,4 +16,42 @@ describe('raf', () => { done(); }); }); + + it('cancel', done => { + let bamboo = false; + + const id = raf(() => { + bamboo = true; + }, 2); + + raf.cancel(id); + + requestAnimationFrame(() => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + expect(bamboo).toBeFalsy(); + done(); + }); + }); + }); + }); + + it('multiple times', done => { + let bamboo = false; + + raf(() => { + bamboo = true; + }, 2); + + expect(bamboo).toBeFalsy(); + + requestAnimationFrame(() => { + expect(bamboo).toBeFalsy(); + + requestAnimationFrame(() => { + expect(bamboo).toBeTruthy(); + done(); + }); + }); + }); });