From 70de8f25f04a64c850018649a4c88e6d94594dfb Mon Sep 17 00:00:00 2001 From: Gabe Klein Date: Fri, 25 Sep 2020 16:25:28 -0600 Subject: [PATCH 1/6] simplify checking for observedNodes' changes --- src/index.ts | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0dffc73..f2f42a8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,30 +1,20 @@ -let props: (keyof DOMRect)[] = [ - "bottom", - "height", - "left", - "right", - "top", - "width", -]; - -let rectChanged = (a: DOMRect = {} as DOMRect, b: DOMRect = {} as DOMRect) => - props.some((prop) => a[prop] !== b[prop]); +let COMPARE_KEYS = [ + "bottom", "height", "left", "right", "top", "width" +] as const; let observedNodes = new Map(); let rafId: number; let run = () => { - const changedStates: RectProps[] = []; observedNodes.forEach((state, node) => { let newRect = node.getBoundingClientRect(); - if (rectChanged(newRect, state.rect)) { - state.rect = newRect; - changedStates.push(state); - } - }); - changedStates.forEach((state) => { - state.callbacks.forEach((cb) => cb(state.rect)); + for(const key of COMPARE_KEYS) + if(newRect[key] !== (state.rect || {})[key]){ + state.rect = newRect; + state.callbacks.forEach(cb => cb(state.rect)) + break; + } }); rafId = window.requestAnimationFrame(run); From 234afce3dab4cb07e6446b8ab75acd7486f304b6 Mon Sep 17 00:00:00 2001 From: Gabe Klein Date: Fri, 25 Sep 2020 16:27:48 -0600 Subject: [PATCH 2/6] tighten up types --- src/index.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index f2f42a8..dace80c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,8 @@ +type RectProps = { + rect: DOMRect; + callbacks: Function[]; +}; + let COMPARE_KEYS = [ "bottom", "height", "left", "right", "top", "width" ] as const; @@ -10,7 +15,7 @@ let run = () => { let newRect = node.getBoundingClientRect(); for(const key of COMPARE_KEYS) - if(newRect[key] !== (state.rect || {})[key]){ + if(newRect[key] !== state.rect[key]){ state.rect = newRect; state.callbacks.forEach(cb => cb(state.rect)) break; @@ -31,8 +36,7 @@ export default function observeRect( observedNodes.get(node)!.callbacks.push(cb); } else { observedNodes.set(node, { - rect: undefined, - hasRectChanged: false, + rect: {} as any, callbacks: [cb], }); } @@ -54,12 +58,4 @@ export default function observeRect( } }, }; -} - -export type PartialRect = Partial; - -export type RectProps = { - rect: DOMRect | undefined; - hasRectChanged: boolean; - callbacks: Function[]; -}; +} \ No newline at end of file From 423ab4ae3e8ab72fa33f64748c173d95eee81f9f Mon Sep 17 00:00:00 2001 From: Gabe Klein Date: Fri, 25 Sep 2020 16:34:35 -0600 Subject: [PATCH 3/6] optimize main loop --- src/index.ts | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/index.ts b/src/index.ts index dace80c..fa75ba4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,22 +8,25 @@ let COMPARE_KEYS = [ ] as const; let observedNodes = new Map(); -let rafId: number; +let active: boolean; -let run = () => { - observedNodes.forEach((state, node) => { - let newRect = node.getBoundingClientRect(); +function checkForUpdates(){ + if(active){ + observedNodes.forEach(assertDidUpdate); + window.requestAnimationFrame(checkForUpdates); + } +}; - for(const key of COMPARE_KEYS) - if(newRect[key] !== state.rect[key]){ - state.rect = newRect; - state.callbacks.forEach(cb => cb(state.rect)) - break; - } - }); +function assertDidUpdate(state: RectProps, node: Element){ + let newRect = node.getBoundingClientRect(); - rafId = window.requestAnimationFrame(run); -}; + for(const key of COMPARE_KEYS) + if(newRect[key] !== state.rect[key]){ + state.rect = newRect; + state.callbacks.forEach(cb => cb(state.rect)) + break; + } +} export default function observeRect( node: Element, @@ -40,7 +43,10 @@ export default function observeRect( callbacks: [cb], }); } - if (wasEmpty) run(); + if (wasEmpty) { + active = true; + checkForUpdates(); + } }, unobserve() { @@ -54,7 +60,8 @@ export default function observeRect( if (!state.callbacks.length) observedNodes.delete(node); // Stop the loop - if (!observedNodes.size) cancelAnimationFrame(rafId); + if (!observedNodes.size) + active = false; } }, }; From 57101bd562006bb337319a58bfd33e7a5aae1fda Mon Sep 17 00:00:00 2001 From: Gabe Klein Date: Fri, 25 Sep 2020 16:39:53 -0600 Subject: [PATCH 4/6] store callbacks in a Set instead of array --- src/index.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/index.ts b/src/index.ts index fa75ba4..adcda8e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ type RectProps = { rect: DOMRect; - callbacks: Function[]; + callbacks: Set; }; let COMPARE_KEYS = [ @@ -30,17 +30,17 @@ function assertDidUpdate(state: RectProps, node: Element){ export default function observeRect( node: Element, - cb: (rect: DOMRect) => void + callback: (rect: DOMRect) => void ) { return { observe() { let wasEmpty = observedNodes.size === 0; if (observedNodes.has(node)) { - observedNodes.get(node)!.callbacks.push(cb); + observedNodes.get(node)!.callbacks.add(callback); } else { observedNodes.set(node, { rect: {} as any, - callbacks: [cb], + callbacks: new Set([callback]), }); } if (wasEmpty) { @@ -52,12 +52,11 @@ export default function observeRect( unobserve() { let state = observedNodes.get(node); if (state) { - // Remove the callback - const index = state.callbacks.indexOf(cb); - if (index >= 0) state.callbacks.splice(index, 1); + state.callbacks.delete(callback); // Remove the node reference - if (!state.callbacks.length) observedNodes.delete(node); + if (!state.callbacks.size) + observedNodes.delete(node); // Stop the loop if (!observedNodes.size) From 1d31a22de0adcdf5b2223516f83401fedab10c07 Mon Sep 17 00:00:00 2001 From: Gabe Klein Date: Fri, 25 Sep 2020 18:08:02 -0600 Subject: [PATCH 5/6] use a closure to assist unobserve --- src/index.ts | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/index.ts b/src/index.ts index adcda8e..15a9315 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,37 +31,37 @@ function assertDidUpdate(state: RectProps, node: Element){ export default function observeRect( node: Element, callback: (rect: DOMRect) => void -) { +){ + let state = observedNodes.get(node); + return { - observe() { - let wasEmpty = observedNodes.size === 0; - if (observedNodes.has(node)) { - observedNodes.get(node)!.callbacks.add(callback); - } else { - observedNodes.set(node, { + observe(){ + if(state) + state.callbacks.add(callback); + else { + observedNodes.set(node, state = { rect: {} as any, callbacks: new Set([callback]), }); - } - if (wasEmpty) { - active = true; - checkForUpdates(); + + if(!active){ + active = true; + checkForUpdates(); + } } }, - - unobserve() { - let state = observedNodes.get(node); - if (state) { + unobserve(){ + if(state){ state.callbacks.delete(callback); - - // Remove the node reference - if (!state.callbacks.size) + + if(!state.callbacks.size) observedNodes.delete(node); - - // Stop the loop - if (!observedNodes.size) + + state = undefined; + + if(!observedNodes.size) active = false; } - }, - }; + } + } } \ No newline at end of file From 2459deb29a199282e4c6997cfb01173f809d50c7 Mon Sep 17 00:00:00 2001 From: Gabe Klein Date: Fri, 25 Sep 2020 18:33:48 -0600 Subject: [PATCH 6/6] indent w spaces instead --- src/index.ts | 94 ++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/index.ts b/src/index.ts index 15a9315..93243d8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,67 +1,67 @@ type RectProps = { - rect: DOMRect; - callbacks: Set; + rect: DOMRect; + callbacks: Set; }; let COMPARE_KEYS = [ - "bottom", "height", "left", "right", "top", "width" + "bottom", "height", "left", "right", "top", "width" ] as const; let observedNodes = new Map(); let active: boolean; function checkForUpdates(){ - if(active){ - observedNodes.forEach(assertDidUpdate); - window.requestAnimationFrame(checkForUpdates); - } + if(active){ + observedNodes.forEach(assertDidUpdate); + window.requestAnimationFrame(checkForUpdates); + } }; function assertDidUpdate(state: RectProps, node: Element){ - let newRect = node.getBoundingClientRect(); + let newRect = node.getBoundingClientRect(); - for(const key of COMPARE_KEYS) - if(newRect[key] !== state.rect[key]){ - state.rect = newRect; - state.callbacks.forEach(cb => cb(state.rect)) - break; - } + for(const key of COMPARE_KEYS) + if(newRect[key] !== state.rect[key]){ + state.rect = newRect; + state.callbacks.forEach(cb => cb(state.rect)) + break; + } } export default function observeRect( - node: Element, - callback: (rect: DOMRect) => void + node: Element, + callback: (rect: DOMRect) => void ){ - let state = observedNodes.get(node); + let state = observedNodes.get(node); - return { - observe(){ - if(state) - state.callbacks.add(callback); - else { - observedNodes.set(node, state = { - rect: {} as any, - callbacks: new Set([callback]), - }); - - if(!active){ - active = true; - checkForUpdates(); - } - } - }, - unobserve(){ - if(state){ - state.callbacks.delete(callback); - - if(!state.callbacks.size) - observedNodes.delete(node); - - state = undefined; - - if(!observedNodes.size) - active = false; - } - } - } + return { + observe(){ + if(state) + state.callbacks.add(callback); + else { + observedNodes.set(node, state = { + rect: {} as any, + callbacks: new Set([callback]), + }); + + if(!active){ + active = true; + checkForUpdates(); + } + } + }, + unobserve(){ + if(state){ + state.callbacks.delete(callback); + + if(!state.callbacks.size) + observedNodes.delete(node); + + state = undefined; + + if(!observedNodes.size) + active = false; + } + } + } } \ No newline at end of file