Skip to content
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

fix(animationFrameScheduler): some tasks are never flushed and sometimes it breaks completely #7444

Open
wants to merge 5 commits into
base: 7.x
Choose a base branch
from

Conversation

pmoleri
Copy link

@pmoleri pmoleri commented Feb 20, 2024

animationFrameScheduler has a few issues that makes it miss tasks and even start accumulating tasks that never get flushed.

  • It's clearing the _scheduled in every flush, but some of the flushes are not for the next scheduled frame, they're regular async timeouts.
  • because it might be picking the incorrect flushId it may flush tasks before the next frame
  • after flushing and recycling the id it's clearing the _scheduled even though current id might be a different one.

Related issues:

Failing tests are included in a independent commit and then fixed.

Note:
The changes could also be ported to AsapScheduler for consistency (also I think it's more clear).
However, I couldn't reproduce the issues there because:

  • AsapScheduler already contains one of the fixes
  • In AsapScheduler I couldn't schedule a task to happen before the _scheduled one.

@pmoleri
Copy link
Author

pmoleri commented Feb 29, 2024

Hi @benlesh. I noticed that you fixed #7196 for asapScheduler, but animationFrameScheduler has similar issue, and worse even (reason explained in this PR description).
Any chance that you can review this PR? It also includes tests that make it fail without the fix.

@BlueCat0
Copy link

BlueCat0 commented Sep 4, 2024

any update yet?

@pmoleri
Copy link
Author

pmoleri commented Sep 4, 2024

@BlueCat0 Unfortunately it seems that no one had the time to review it.
Once you understand the code (which takes a while) the bug is pretty clear and the resolution too.

To avoid the bug altogether, never use animationFrameScheduler with a delay, you can use the asyncScheduler for that purpose. In fact they would behave exactly the same, as animationFrameScheduler doesn't really schedule into a frame when delay is used.

Note that using animationFrameScheduler with a delay in one place may impact in a different place.

@ChristophWieske
Copy link

@pmoleri Your PR is open for quite some time. Has there been another PR which made yours obsolete? Or is this still waiting for a review?

I encounter issues with animationFrameScheduler in 7.8.1 which are maybe related.

So, is the bug you are trying to fix here still unfixed?

@pmoleri
Copy link
Author

pmoleri commented Jan 17, 2025

Hi @ChristophWieske

The issue is actually quite serious, it can affect any Angular app combining animationFrameScheduler with a delay other than 0.
It's very hard to troubleshoot, it leads to anomalous behavior or crashes depending on the case.

In the 7.x branch the files have not been touched in 3 years, so I'm positive that the issue is still there.
I've included tests to make it fail (if you omit the fix).

In master the files have been moved around and the imports changed but the code is exactly the same.
So it must happen too.

@pmoleri
Copy link
Author

pmoleri commented Jan 20, 2025

Hi @benlesh. This PR fixes real bugs and it has tests to confirm the bug and the fix.
The changes are small and I consider them sound.

I made the PR to 7.x, but I could re-target to master and backport later.
I can make the changes that you consider best. Thanks.

});

// This action will execute before the next frame because the delay is less than the one of the frame
animationFrame.schedule(() => { runDelayed = true; }, 1);
Copy link
Member

@trxcllnt trxcllnt Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious the order in which these actions are expected to execute.

Is runFirst expected to be true when runDelayed is set to true? e.g.:

Suggested change
animationFrame.schedule(() => { runDelayed = true; }, 1);
animationFrame.schedule(() => {
if (!runFirst) {
done(new Error('First action did not run'));
} else {
runDelayed = true;
}
}, 1);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's the opposite. The action queued with a delay smaller than animationFrame runs first.
That's how animationFrameScheduler is implemented, actions with delay other than zero are scheduled purely based on time and not actual animation frames.
I'll push a change to make it more clear.

Copy link
Author

@pmoleri pmoleri Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There. I pushed the change. Now each scheduled action asserts the previous one. Instead of having everything in the last one.

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.

4 participants