-
Notifications
You must be signed in to change notification settings - Fork 207
feat: use yielding to main thread in more places #2585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6 files reviewed, 4 comments
|
Size Change: +19.5 kB (+0.39%) Total Size: 5.04 MB
ℹ️ View Unchanged
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new TaskQueue utility to improve page responsiveness by breaking up CPU-intensive operations and yielding to the main thread periodically. This helps reduce Interaction to Next Paint (INP) variability on pages with heavy processing.
- Adds a reusable
TaskQueueclass with time-budgeting (default 30ms) to avoid blocking the main thread - Implements helper functions
processWithYieldandprocessAsyncWithYieldfor common array processing patterns - Integrates the task queue into request queue flushing, extension initialization, performance entry processing, and session recording event handling
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/browser/src/utils/task-queue.ts | New task queue implementation with time-slicing support and helper functions for processing arrays with yielding |
| packages/browser/src/utils/tests/task-queue.test.ts | Comprehensive test suite covering task queue functionality, error handling, and yielding behavior |
| packages/browser/src/request-queue.ts | Updates flush callback to use processWithYield for processing request batches |
| packages/browser/src/posthog-core.ts | Refactors extension initialization to use TaskQueue class, removing custom time-slicing logic |
| packages/browser/src/extensions/replay/external/network-plugin.ts | Applies yielding to initial performance entry processing |
| packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts | Adds yielding to queued event processing |
| .changeset/smooth-wolves-mix.md | Changeset documenting the new feature |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts
Show resolved
Hide resolved
5b464a3 to
dcd9d73
Compare
dcd9d73 to
e1fa634
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts
Outdated
Show resolved
Hide resolved
e1fa634 to
6e5b1cb
Compare
6e5b1cb to
d0eb1ea
Compare
d0eb1ea to
48f90cd
Compare
48f90cd to
17209ef
Compare
| @@ -1,5 +1,5 @@ | |||
| module.exports = { | |||
| testPathIgnorePatterns: ['/node_modules/', '/cypress/', '/react/', '/test_data/', '/testcafe/'], | |||
| testPathIgnorePatterns: ['/node_modules/', '/cypress/', '/react/', '/test_data/', '/testcafe/', '\\.d\\.ts$'], | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look right, you're escaping the slash rather than the dot?
Shouldn't it be \.d'\.ts$?
| logger.error('Error initializing extension:', error) | ||
| }, | ||
| }) | ||
| taskQueue.enqueueAll(initTasks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we not need to call a method to actually start the processing?
| @@ -0,0 +1,210 @@ | |||
| /** | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't exactly like how we need to use this class, but it works, so please just merge if you think this is good.
IMO the way we should consume this is new AsyncProcessor(iterator, { timeBudgetMs: 30 }).processEach(item => doSomething(item))
This is definitely different from your idea where each item in the array is a function and you're just calling those functions, BUT it does align more with how you're using this class (list of items that need to be processed iwth the same function everytime). It basically means to me you're trying to use the wrong abstraction for the job, hence why you had to add those 2 helper functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
list of items that need to be processed iwth the same function everytime
hmmm, that's not the abstraction though
this is
list of tasks that need to be processed
they could be the same task many times but they don't have to be
right now, there's no shared task queue, but we could end up with a shared task queue, so i tried to keep it that way
(all replaceable though so 🙈)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that's exactly my point: the abstraction is "list of task that needs to be processed" while the usage is "list of items that need to be processed with the same function at all times".
If the abstraction wasn't wrong we wouldn't need that processWithYield helper where we pass the same function at all times 😇
btw, can we add an underscore to these functions by any chance to make sure people understand they're private? we need to make (all replaceable though so 🙈) true lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, will absorb this when my brain is not offsite-tired 😆
| useEffect(() => { | ||
| posthog.init('phc_test_key_for_playground', { | ||
| api_host: '/ph-relay-xyz123', | ||
| posthog.init('sTMFPsFhdP1Ssg', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't add our production key here, people already use our key on their apps just because we have it on our posthog repo , we don't need even more people using it 😥

we tested yielding processing to the main thread periodically and it worked well
reducing variability of INP on pages using that mode
let's abstract the task queue processing approach and use it in a few more places where we might be running over large arrays and cause a long task