feat(runtime): requestAnimationFrame and Android-parity frame callbacks - #446
Conversation
Add a CADisplayLink-backed AnimationFrame module registering two surfaces on every global (workers included): - requestAnimationFrame/cancelAnimationFrame with spec semantics: one one-shot entry per request, a returned handle, cancellation by handle, and a single performance-timeline timestamp argument. - __postFrameCallback(fn[, delayMillis])/__removeFrameCallback(fn), matching the Android runtime's contract: dedup by function identity via a private value, fn(frameTimeNanos, performanceMillis), and delayed entries firing on the first frame after the delay elapses. The per-isolate display link is created paused on the isolate's home runloop in the common modes and only runs while entries are pending, so an idle isolate never wakes per frame. Frame timestamps map CADisplayLink.timestamp (mach_absolute_time base, shared with the V8 platform clock) onto the performance timeline through the runtime's monotonic time origin, so every callback in a batch observes the vsync instant rather than dispatch time. QuartzCore is now linked into the NativeScript target, which autolinks nothing.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughAdds iOS animation-frame support for each V8 isolate. It exposes standard and compatibility callback APIs, schedules callbacks through ChangesAnimation frame runtime
Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: ⚪ Minimal · up to The PR adds frame-callback APIs with runtime, test, and build integration; no actionable merge-blocking risk remains beyond normal checks and review. Sequence Diagram(s)sequenceDiagram
participant JavaScript
participant AnimationFrame
participant CADisplayLink
participant V8Isolate
JavaScript->>AnimationFrame: requestAnimationFrame(callback)
AnimationFrame->>CADisplayLink: schedule display-link callback
CADisplayLink->>AnimationFrame: provide frame timestamp
AnimationFrame->>V8Isolate: enter isolate and dispatch callbacks
V8Isolate->>JavaScript: invoke callback with timestamp
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What
Adds a CADisplayLink-backed
AnimationFramemodule exposing two frame-callback surfaces on every global (workers included):requestAnimationFrame(fn)/cancelAnimationFrame(handle)— spec semantics: every request registers its own one-shot entry and returns a numeric handle; cancellation is by handle (and can only touch rAF entries);fnreceives a singleDOMHighResTimeStampon the isolate's performance timeline.__postFrameCallback(fn[, delayMillis])/__removeFrameCallback(fn)— the Android runtime's compatibility contract (NativeScript/android@d1fc925f): one-shot, deduped by function identity via a_postFrameCallbackIdprivate value (re-posting a pending callback is a no-op),fn(frameTimeNanos, performanceMillis), TypeError on non-function arguments, and delayed entries firing on the first frame after the delay elapses.How
CADisplayLinkper isolate, created paused during isolate init on the home thread and attached to that thread's runloop in the common modes (same modes as the EventLoop's timers, so ticks keep arriving during scroll tracking). Posting unpauses it; an empty registry pauses it again, so an idle isolate never wakes per frame.CADisplayLink.timestampshares themach_absolute_timebase with the V8 platform clock, so the vsync instant maps onto the performance timeline throughRuntime::TimeOriginMonotonicSeconds()— callbacks observe the frame time, not dispatch time, and every callback in a batch sees the same timestamps.Caches::registerCacheBoundObject, torn down beforeIsolate::DisposelikeTimerState), so unlike the Android implementation's process-global map, no locking is needed.QuartzCoreinto the NativeScript target (it autolinks nothing, and UIKit alone does not resolveCADisplayLinkunder explicit-frameworklinking).Tests
TestRunner/app/tests/AnimationFrameTests.jsports the AndroidtestPostFrameCallback.jssuite (existence, argument TypeErrors, single-fire, dedup on double-post, cancel/cancel-then-repost, self-reschedule, GC retention/release) and adds rAF specs (handle + single timestamp arg, once-per-request for the same function, targeted cancellation, batch timestamp equality, frame chaining, dedupe isolation from__postFrameCallback), a delay spec, and a frame-time/performance-timestamp spec. Full suite green locally on the iOS simulator.Summary by CodeRabbit
New Features
requestAnimationFrameandcancelAnimationFrameAPIs on iOS.__postFrameCallbackand__removeFrameCallback.Tests