Skip to content

Fix ignored setState in Safari when iframe is touched#24459

Merged
gaearon merged 1 commit into
react:mainfrom
gaearon:safari-flush-early
May 12, 2022
Merged

Fix ignored setState in Safari when iframe is touched#24459
gaearon merged 1 commit into
react:mainfrom
gaearon:safari-flush-early

Conversation

@gaearon

@gaearon gaearon commented Apr 28, 2022

Copy link
Copy Markdown
Collaborator

Fixes #24458.

Just like #22459, this is caused by a Safari bug (https://bugs.webkit.org/show_bug.cgi?id=235322).

Our original solution for #22459 was #23111: if the microtask callback runs prematurely, we ignore it. This relied on the assumption that we always check for more work at the end of the task anyway. However, we don't check for more work if we aren't either rendering or committing — notably, we don't check for more work at the end of the event handler.

This fix is to allow the update to flush early. This doesn't respect batching but matches what Safari is trying to do (which is to flush everything early).

@gaearon gaearon requested review from acdlite and sebmarkbage April 28, 2022 16:41
@facebook-github-bot facebook-github-bot added the React Core Team Opened by a member of the React Core Team label Apr 28, 2022
@sizebot

sizebot commented Apr 28, 2022

Copy link
Copy Markdown

Comparing: 340060c...b7b40cd

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js = 131.58 kB 131.58 kB = 42.11 kB 42.11 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js = 136.82 kB 136.82 kB = 43.69 kB 43.69 kB
facebook-www/ReactDOM-prod.classic.js = 441.17 kB 441.18 kB = 80.49 kB 80.49 kB
facebook-www/ReactDOM-prod.modern.js = 426.38 kB 426.39 kB = 78.29 kB 78.29 kB
facebook-www/ReactDOMForked-prod.classic.js = 441.17 kB 441.18 kB = 80.49 kB 80.49 kB

Significant size changes

Includes any change greater than 0.2%:

(No significant changes)

Generated by 🚫 dangerJS against b7b40cd

queue.forEach(cb => cb());
queue = [];
flushMicrotasksPrematurely = function() {
while (queue.length > 0) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This simulates the Safari behavior of trying to drain the queue until it's empty. So that we don't "fix" this by adding an infinite loop.

Proof:

<body>
<script>
let busy = true
const callback = () => {
  if (busy) {
    console.error('noo im busy')
    queueMicrotask(callback)
  } else {
    console.log('im ok')
  }
}
queueMicrotask(callback);
console.log("will add iframe");
const iframe = document.createElement("iframe");
iframe.src = "localhost";
document.body.appendChild(iframe);
console.log("did add iframe");
busy = false
</script>
</body>

gets Safari infinitely stuck

@gaearon

gaearon commented May 6, 2022

Copy link
Copy Markdown
Collaborator Author

ping @acdlite

@gaearon gaearon merged commit 2c8a145 into react:main May 12, 2022
@gaearon gaearon deleted the safari-flush-early branch May 12, 2022 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: setState is not flushed if an iframe is added in the same tick in Safari

4 participants