Skip to content

Commit

Permalink
Fix development mode hang when iframe is removed (#19220)
Browse files Browse the repository at this point in the history
* Fix development mode hang when iframe is removed

* Also fix #16734
  • Loading branch information
gaearon committed Jul 1, 2020
1 parent 8bff898 commit f918b0e
Showing 1 changed file with 33 additions and 11 deletions.
44 changes: 33 additions & 11 deletions packages/shared/invokeGuardedCallbackImpl.js
Expand Up @@ -9,7 +9,7 @@

import invariant from 'shared/invariant';

let invokeGuardedCallbackImpl = function<A, B, C, D, E, F, Context>(
function invokeGuardedCallbackProd<A, B, C, D, E, F, Context>(
name: string | null,
func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
context: Context,
Expand All @@ -26,7 +26,9 @@ let invokeGuardedCallbackImpl = function<A, B, C, D, E, F, Context>(
} catch (error) {
this.onError(error);
}
};
}

let invokeGuardedCallbackImpl = invokeGuardedCallbackProd;

if (__DEV__) {
// In DEV mode, we swap out invokeGuardedCallback for a special version
Expand Down Expand Up @@ -58,7 +60,15 @@ if (__DEV__) {
) {
const fakeNode = document.createElement('react');

const invokeGuardedCallbackDev = function<A, B, C, D, E, F, Context>(
invokeGuardedCallbackImpl = function invokeGuardedCallbackDev<
A,
B,
C,
D,
E,
F,
Context,
>(
name: string | null,
func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
context: Context,
Expand All @@ -85,6 +95,7 @@ if (__DEV__) {
);
const evt = document.createEvent('Event');

let didCall = false;
// Keeps track of whether the user-provided callback threw an error. We
// set this to true at the beginning, then set it to false right after
// calling the function. If the function errors, `didError` will never be
Expand All @@ -105,11 +116,7 @@ if (__DEV__) {
'event',
);

// Create an event handler for our fake event. We will synchronously
// dispatch our fake event using `dispatchEvent`. Inside the handler, we
// call the user-provided callback.
const funcArgs = Array.prototype.slice.call(arguments, 3);
function callCallback() {
function restoreAfterDispatch() {
// We immediately remove the callback from event listeners so that
// nested `invokeGuardedCallback` calls do not clash. Otherwise, a
// nested call would trigger the fake event handlers of any call higher
Expand All @@ -126,7 +133,15 @@ if (__DEV__) {
) {
window.event = windowEvent;
}
}

// Create an event handler for our fake event. We will synchronously
// dispatch our fake event using `dispatchEvent`. Inside the handler, we
// call the user-provided callback.
const funcArgs = Array.prototype.slice.call(arguments, 3);
function callCallback() {
didCall = true;
restoreAfterDispatch();
func.apply(context, funcArgs);
didError = false;
}
Expand Down Expand Up @@ -183,7 +198,7 @@ if (__DEV__) {
Object.defineProperty(window, 'event', windowEventDescriptor);
}

if (didError) {
if (didCall && didError) {
if (!didSetError) {
// The callback errored, but the error event never fired.
error = new Error(
Expand All @@ -208,9 +223,16 @@ if (__DEV__) {

// Remove our event listeners
window.removeEventListener('error', handleWindowError);
};

invokeGuardedCallbackImpl = invokeGuardedCallbackDev;
if (!didCall) {
// Something went really wrong, and our event was not dispatched.
// https://github.com/facebook/react/issues/16734
// https://github.com/facebook/react/issues/16585
// Fall back to the production implementation.
restoreAfterDispatch();
return invokeGuardedCallbackProd.apply(this, arguments);
}
};
}
}

Expand Down

0 comments on commit f918b0e

Please sign in to comment.