Skip to content

feat(data): optional preload scheduler for AsyncDataService.createLazy - #171

Open
kunalkindra wants to merge 3 commits into
mainfrom
kkindra/create-lazy-preload
Open

feat(data): optional preload scheduler for AsyncDataService.createLazy#171
kunalkindra wants to merge 3 commits into
mainfrom
kkindra/create-lazy-preload

Conversation

@kunalkindra

Copy link
Copy Markdown
Collaborator

What

Adds an optional third options argument to AsyncDataService.createLazy with a preload scheduler:

interface CreateLazyOptions {
  preload?: (warm: () => void) => void;
}

It is invoked once when the factory creates a lazy service instance, receiving a warm callback that eagerly triggers the real load — constructing the service before its first property is touched. Fully backward compatible: omit options (or options.preload) and the existing load-on-first-touch behavior is unchanged.

Why

A lazy service loads only when its first property is accessed. That keeps heavy imports out of the initial bundle, but the very first send / read / call pays for the load — and when that first touch happens right before the page tears down (e.g. an analytics event fired immediately before a navigation), the load can lose the race and the call is dropped.

preload closes that gap without giving up laziness. The caller owns the policy (when to warm — at browser idle, eagerly, after first input), while createLazy owns the mechanism (invoking load and memoizing). Because loading is idempotent, warm is safe to call any number of times and dedupes with the first real property access. The framework stays environment-agnostic — browser concerns like requestIdleCallback live in the caller's scheduler:

const createLazyAnalytics = AsyncDataService.createLazy(
  () => import('./analytics').then(m => m.create()),
  { send: 'fn:void', pageload: 'fn:void' },
  { preload: (warm) => requestIdleCallback(warm) }
);

Tests

Five new cases in create-lazy.test.ts: no-load without the option, scheduler invoked with warm on instance creation, warm loads before any property touch, warm dedupes with the first real touch, queued calls still drain after a preload. create-lazy.md documents the option. Local pnpm typecheck, pnpm lint, check:workspace, and the full data-package test suite (44/44) pass.

kunalkindra and others added 3 commits August 14, 2026 17:32
A lazy service loads only when its first property is touched. That keeps
heavy imports out of the initial bundle, but the first send/read/call pays
for the load — and when that first touch happens right before the page
tears down (e.g. an analytics event fired immediately before navigation),
the load can lose the race and the call is dropped.

Add an optional third `options` arg with a `preload` scheduler. It is
invoked once per instance with a `warm` callback that eagerly triggers the
real load. The caller owns the policy (when to warm — idle, eager, after
first input); createLazy owns the mechanism (invoking `load`, memoizing).
`warm` is idempotent and dedupes with the first real property access.

Fully backward compatible: omitting `options` keeps the existing
load-on-first-touch behavior. The framework stays environment-agnostic —
browser concerns like requestIdleCallback live in the caller's scheduler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Documents contributing from a personal GitHub identity when a corporate/EMU
account can't fork or push to the public repo, using ~/.ssh/config host aliases
with IdentitiesOnly. Requested during review of the createLazy preload PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ships a ready-made preload scheduler so callers of createLazy's preload option
don't have to hand-roll (and get subtly wrong) the requestIdleCallback glue.
AsyncDataService.preloadWhenIdle warms a lazy service at browser idle via
requestIdleCallback (setTimeout fallback for older Safari), runs once, never
throws, and is a no-op outside a browser.

Exported under the AsyncDataService namespace; createLazy's core stays
environment-agnostic since the browser API lives only in this opt-in helper.
Usage: createLazy(load, props, { preload: AsyncDataService.preloadWhenIdle }).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant