github spaansba/ForesightJS js.foresight@4.2.1

4 hours ago

Patch Changes

  • #168 dfb88f3 Thanks @spaansba! - Fix lazy predictor connects leaking global listeners when a handler disconnects mid-import. DesktopHandler.connectTabPredictor/connectScrollPredictor and TouchDeviceHandler.setTouchPredictor now re-check isConnected after the dynamic import() resolves, so a predictor whose handler disconnected during loading no longer attaches keydown/focusin/pointerdown listeners that never get aborted.

  • #158 8250ad8 Thanks @spaansba! - CircularBuffer now exposes peekWriteSlot() for zero-allocation slot reuse and drops the unused getFirstLast() tuple accessor in favor of getFirst()/getLast().

  • #163 53ef414 Thanks @spaansba! - Drop 4 redundant if (!this.isSetup) guards around initializeGlobalListeners(). The method already self-guards on isSetup, so the outer checks were dead weight.

  • #167 21f066a Thanks @spaansba! - Store event listeners in a Set instead of an array. Iterating a Set during emit means a listener that unsubscribes another mid-dispatch no longer causes the next listener to be skipped, and registration now dedupes like the DOM addEventListener.

  • #171 31d9222 Thanks @spaansba! - Derive ForesightEvent from keyof ForesightEventMap instead of hand-duplicating the event names, so adding an event to the map no longer requires updating the union in lockstep.

  • #159 1de7d1c Thanks @spaansba! - Skip building the callbackInvoked and callbackCompleted event payloads when no one is subscribed. Both emits now sit behind a hasListeners guard, avoiding a per-callback object allocation and, for callbackCompleted, the activeElementCount scan that fed its wasLastActiveElement field.

  • #174 f1e06e6 Thanks @spaansba! - Element state and bounds subscriber Sets are now created on first subscribe instead of eagerly at registration. Headless and plain-JS usage that registers elements but never subscribes to reactive state (the common case outside the framework wrappers) no longer allocates two empty Sets per element.

  • #166 ef09598 Thanks @spaansba! - Simplify loadedPredictors.mouse to a constant since mousePredictor is never null.

  • #157 502cb8d Thanks @spaansba! - Register the global pointermove listener as passive, letting the browser dispatch high-frequency pointer events without treating them as cancelable. Reduces main-thread scheduling pressure during fast mouse movement and scrolling.

  • #162 b6c50f1 Thanks @spaansba! - Remove unused CircularBuffer members (clear, size, isFull, isEmpty) that were only referenced by tests.

  • #170 8dc9f8e Thanks @spaansba! - The mouse trajectory scan now iterates a precomputed set of scannable elements (on-screen, active, not yet predicted) instead of walking the full registry and re-checking those flags every pointer move. Membership is kept in sync on registration, state changes, and unregistration. Cost now scales with the number of visible elements rather than the total registered, so pages with many registered but few on-screen elements run the per-frame scan dramatically faster with no change at small element counts.

  • #164 4dd5947 Thanks @spaansba! - Extract scheduleReactivateTimeout to remove three copy-pasted reactivation-timeout setTimeout blocks, mirroring the existing clearReactivateTimeout.

  • #169 b46a3fd Thanks @spaansba! - ScrollPredictor no longer caches a "none" scroll direction for the whole handlePositionChange batch. A non-moving element (e.g. position:fixed) returning "none" used to poison the cached direction and silently disable scroll prefetch for every later element that actually moved. The direction is now only locked in once a real direction is found.

  • #161 ab0798f Thanks @spaansba! - predictNextScrollPosition now writes into a caller-owned out point instead of allocating a new one per call, matching predictNextMousePosition. ScrollPredictor reuses a single predicted-point object across the batch, removing the per-scroll-batch allocation.

  • #174 5cbefa6 Thanks @spaansba! - applySettingsChanges now returns just the changed-settings array instead of that array plus six hand-wired side-effect booleans. alterGlobalSettings derives a Set of changed keys and checks changed.has(...), so adding a setting no longer means keeping a parallel flag struct in sync in three places.

  • #173 51cd5fd Thanks @spaansba! - Share a base factory between createElementInternal and createUnregisteredSnapshot so the full ForesightElementState field list is only written once, preventing the snapshot from silently drifting when a field is added.

  • #174 f1e06e6 Thanks @spaansba! - Share a single frozen empty meta object across element states instead of allocating a fresh {} per element. The state snapshot is immutable and meta is never mutated in place, so registered elements without a meta and unregistered snapshots now reuse one object.

Don't miss a new ForesightJS release

NewReleases is sending notifications on new releases.