Skip to content

Implement RFC #957: Render Aware Scheduler Interface#21493

Draft
NullVoxPopuli-ai-agent wants to merge 1 commit into
emberjs:mainfrom
NullVoxPopuli-ai-agent:scheduler-interface
Draft

Implement RFC #957: Render Aware Scheduler Interface#21493
NullVoxPopuli-ai-agent wants to merge 1 commit into
emberjs:mainfrom
NullVoxPopuli-ai-agent:scheduler-interface

Conversation

@NullVoxPopuli-ai-agent

Copy link
Copy Markdown
Contributor

Implements the additive API surface of RFC #957 — Render Aware Scheduler Interface (0957-modernized-scheduler).

What this adds

@ember/scheduler

  • render(), layout(), composite(), next(), idle() — one function per phase from the RFC, each returning a promise that resolves according to the registered scheduling strategy:

    import { render, layout, composite } from '@ember/scheduler';
    
    async function repositionTooltip(tooltip) {
      await render();    // updated DOM exists, before paint
      await layout();    // read DOM, before paint
      let rect = tooltip.target.getBoundingClientRect();
      await composite(); // write DOM, before paint
      tooltip.element.style.transform = `translate(${rect.x}px, ${rect.y}px)`;
    }
  • registerStrategy(strategy) — registers the strategy (an implementation of the RFC's Strategy interface) that the phase functions delegate to, intended to be called once when defining the Application. Per the RFC, the strategy holds no callbacks — it only decides when each phase's promise resolves — so scheduled work keeps its async stack traces and cancellation is handled at the call site.

@ember/scheduler/strategy

The default strategy. It models work as belonging to a Frame and flushes the renderlayoutcomposite windows in order within a single frame, before the next paint, by registering ordered requestAnimationFrame callbacks (microtasks — and therefore work awaiting a phase — flush between them). Semantics follow the RFC's examples:

  • scheduling into a phase the current frame hasn't reached yet resolves just-in-time within the current frame
  • scheduling into render while the render window is flushing resolves within the current window (recursive render)
  • scheduling into a phase the current frame has already flushed (or into layout/composite during their own window) resolves in the next frame
  • next() resolves in a task after the current frame completes; idle() uses requestIdleCallback where available
  • in environments without requestAnimationFrame (SSR/FastBoot), phases degrade to FIFO timers

What this intentionally does not do (yet)

The RFC's migration story — deprecating @ember/runloop/RSVP, the use-async-scheduler optional feature flag, mapping schedule('render'/'afterRender') onto the new interface, and evolving the reactivity system to schedule renders — is left to follow-up PRs. This PR establishes the public interface and default strategy so that exploration can begin, matching the RFC's intent that strategies be swappable.

Testing

  • browser tests for the phase-delegation/registration API and for the default strategy's frame semantics (packages/@ember/scheduler/tests)
  • type tests (type-tests/@ember/scheduler-test.ts)
  • YUIDoc for all new public API, wired into tests/docs/expected.cjs

🤖 Generated with Claude Code

Adds the `@ember/scheduler` package proposed by RFC 0957:

- `render`, `layout`, `composite`, `next` and `idle` phase functions,
  each returning a promise that resolves according to the registered
  scheduling strategy
- `registerStrategy`, for providing the scheduling strategy when defining
  the Application
- `@ember/scheduler/strategy`, the default strategy implementation, which
  flushes the render/layout/composite phases in order via ordered
  requestAnimationFrame callbacks within a single frame, prior to paint

The deprecations of @ember/runloop and RSVP described by the RFC are left
to follow-up work; this is the additive API surface.

Co-Authored-By: Claude Fable 5 <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.

2 participants