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

Under what circumstances, unstable_shouldYield will return true? #14796

Closed
xilixjd opened this issue Feb 8, 2019 · 4 comments
Closed

Under what circumstances, unstable_shouldYield will return true? #14796

xilixjd opened this issue Feb 8, 2019 · 4 comments

Comments

@xilixjd
Copy link

xilixjd commented Feb 8, 2019

In Scheduler.js,

function unstable_shouldYield() {
  return (
    !currentDidTimeout &&
    ((firstCallbackNode !== null &&
      firstCallbackNode.expirationTime < currentExpirationTime) ||
      shouldYieldToHost())
  );
}

unstable_shouldYield() return true when currentDidTimeout is false and shouldYieldToHost() return true, but why?

shouldYieldToHost = function() {
  return frameDeadline <= getCurrentTime();
};

shouldYieldToHost() return true means there's no time left in this idle period
currentDidTimeout is false means the schedule is not timeout
what relationship between them, why does unstable_shouldYield() depend on them?

@sophiebits
Copy link
Collaborator

We yield to the host environment periodically – every 16ms or so – to allow the browse to process incoming events including user input. frameDeadline is the timestamp that we plan to yield at (originally set to something like now() + 16ms), so shouldYieldToHost returns true once that time has passed. Then we use some combination of requestIdleCallback and requestAnimationFrame so we can process the next piece of work soon.

In the ideal case, we can finish all of the rendering in these small 16ms slices. However, if there are many other things happening at the same time, React work may "starve" and not be able to fully render in the small slices. So we have a second check: every pending render or state update has an "expiration time" (usually somewhere from 100ms to 5000ms) – if that time passes without the render finishing, we switch to a synchronous mode until that update can be finished. This is not ideal but it ensures that all updates get processed without waiting too long.

We set a timer in the browser (e.g., with setTimeout) for that same expiration time. If that timer fires, we know we need to perform the work synchronously. If this happens, currentDidTimeout is set to true, so we won't yield.

In the future, we plan to use a new isInputPending browser API (https://github.com/WICG/is-input-pending) so we can continue processing work and only yield when there is new user input, instead of always yielding every 16ms.

@xilixjd
Copy link
Author

xilixjd commented Feb 10, 2019

Thanks for reply
I still have some questions,

  1. I think unstable_shouldYield() represent for whether the work can be interrupted or not in the schedule,is that correct?
  2. Does the "16ms" refer to activeFrameTime?
  3. When will firstCallbackNode.expirationTime < currentExpirationTime return true ? Does that mean the next work's priority is higher than the previous one?

@sophiebits
Copy link
Collaborator

  1. Each rendering task should check unstable_shouldYield() frequently. (We call it roughly after each component in the tree.) Most of the time it will return false (which means keep going) but when it returns true that means the rendering needs to pause.

  2. Yes.

  3. I believe that condition is true if some newer, higher-priority work is enqueued during an existing render. In that case, we want to return true so that we can switch to that task.

@xilixjd
Copy link
Author

xilixjd commented Feb 10, 2019

Thank you very much.It's really nice of you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants