fix(scheduler): should insert jobs in ascending order of job's id when flushing #3184
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fix: #2768, Fix #2829
what's happened?
Let's talk about what happened first, well, they are very complex issues(#2768, #2829). I tried to point out the minimum reproduction, check out https://codesandbox.io/s/nifty-glitter-u11y9?file=/src/index.ts, it's based on #2768. I will use the reproduced code to illustrate what happened.
Take a look at the complete code:
Yes, it contains some code generated by the compiler (such as
createBlock
etc.), this is because we have to reproduce the problem based on that.There are
6
components here. After the first rendering is completed,7
component instances will be created(theWrap
component rendered twice), there is also a computed value(outerCompute
), they all create aneffect
function, and the ids of theseeffect
functions are incremented in the order they were created. We can useComp(effect id)
to express, for example,Root(0)
represents the rendereffect
function of theRoot
component, and itsid
is0
, the complete list is:Root(0)
Computed(1)
- computed's effectOuter(2)
Inner(3)
Wrap(4)
- as Inner's childIssueComp(5)
- It is the problematic componentWrap(6)
- as Outer's childTest(7)
Start by toggle the value of
rootRef
:Will do these detailed steps:
Conclusion:
Wrap(4)
was skipped, which means theIssueComp
will not be updatedStep
8
is the problematic point:invalidateJob(Test(7))
shortens the queue's length, butflushIndex
remains the same, which makes subsequent tasks skipped(Wrap(4)
).Of course we can use the changes introduced by @edison1105 in its PR(#2834) to fix the bug, but please pay attention to the above steps, there are still problems there:
Test(7)
was patched twice because it entered the queue prematurely:Do the first patch in step
6
:Made the second patch in step 8:
You can verify it by modifying the
Test
component:How to fix that?
You may have noticed that the order in which jobs are enqueued is not the order of increasing id:
[Root(0), Test(7), Wrap(6), Wrap(4)]
, but when we start to flush the queue, we expect jobs to be executed in ascending order of id, so we can keep the order when the job is enqueued, which can prevent the job from being skipped and also can avoid repeated patching. We can use binary-search to find a suitable position in the queue. I think its cost is less than the cost of repeated patching.