@samitouri / QOS-React / commits / 8feeed10d8

[scheduler] Remove window.postMessage fallback

Every browser we can about supports MessageChannel. The ones we don't care about will fallback to the setTimeout implementation.

Andrew Clark committed Nov 14, 2018 at 14:33 UTC 8feeed10d8f79a0c01ca293890880cbe72b3788d
4 files changed +17 -47
packages/react-dom/src/__tests__/ReactDOM-test.js
-16
@@ -450,22 +450,6 @@ describe('ReactDOM', () => {
450 }
451 });
452
453 - it('warns when requestAnimationFrame is not polyfilled', () => {
454 - const previousRAF = global.requestAnimationFrame;
455 - try {
456 - delete global.requestAnimationFrame;
457 - jest.resetModules();
458 - spyOnDevAndProd(console, 'error');
459 - require('react-dom');
460 - expect(console.error.calls.count()).toEqual(1);
461 - expect(console.error.calls.argsFor(0)[0]).toMatch(
462 - "This browser doesn't support requestAnimationFrame.",
463 - );
464 - } finally {
465 - global.requestAnimationFrame = previousRAF;
466 - }
467 - });
468 -
453 it('reports stacks with re-entrant renderToString() calls on the client', () => {
454 function Child2(props) {
455 return <span ariaTypo3="no">{props.children}</span>;
packages/scheduler/src/Scheduler.js
+7 -29
@@ -457,9 +457,8 @@ if (typeof window !== 'undefined' && window._schedMock) {
457 // If Scheduler runs in a non-DOM environment, it falls back to a naive
458 // implementation using setTimeout.
459 typeof window === 'undefined' ||
460 - // "addEventListener" might not be available on the window object
461 - // if this is a mocked "window" object. So we need to validate that too.
462 - typeof window.addEventListener !== 'function'
460 + // Check if MessageChannel is supported, too.
461 + typeof MessageChannel !== 'function'
462 ) {
463 var _callback = null;
464 var _currentTime = -1;
@@ -533,17 +532,9 @@ if (typeof window !== 'undefined' && window._schedMock) {
532 };
533
534 // We use the postMessage trick to defer idle work until after the repaint.
536 - var port = null;
537 - var messageKey =
538 - '__reactIdleCallback$' +
539 - Math.random()
540 - .toString(36)
541 - .slice(2);
542 - var idleTick = function(event) {
543 - if (event.source !== port || event.data !== messageKey) {
544 - return;
545 - }
546 -
535 + var channel = new MessageChannel();
536 + var port = channel.port2;
537 + channel.port1.onmessage = function(event) {
538 isMessageEventScheduled = false;
539
540 var prevScheduledCallback = scheduledHostCallback;
@@ -627,7 +618,7 @@ if (typeof window !== 'undefined' && window._schedMock) {
618 frameDeadline = rafTime + activeFrameTime;
619 if (!isMessageEventScheduled) {
620 isMessageEventScheduled = true;
630 - port.postMessage(messageKey, '*');
621 + port.postMessage('*');
622 }
623 };
624
@@ -636,7 +627,7 @@ if (typeof window !== 'undefined' && window._schedMock) {
627 timeoutTime = absoluteTimeout;
628 if (isFlushingHostCallback || absoluteTimeout < 0) {
629 // Don't wait for the next frame. Continue working ASAP, in a new event.
639 - port.postMessage(messageKey, '*');
630 + port.postMessage('*');
631 } else if (!isAnimationFrameScheduled) {
632 // If rAF didn't already schedule one, we need to schedule a frame.
633 // TODO: If this rAF doesn't materialize because the browser throttles, we
@@ -647,19 +638,6 @@ if (typeof window !== 'undefined' && window._schedMock) {
638 }
639 };
640
650 - if (typeof MessageChannel === 'function') {
651 - // Use a MessageChannel, if support exists
652 - var channel = new MessageChannel();
653 - channel.port1.onmessage = idleTick;
654 - port = channel.port2;
655 - } else {
656 - // Otherwise post a message to the window. This isn't ideal because message
657 - // handlers will fire on every frame until the queue is empty, including
658 - // some browser extensions.
659 - window.addEventListener('message', idleTick, false);
660 - port = window;
661 - }
662 -
641 cancelHostCallback = function() {
642 scheduledHostCallback = null;
643 isMessageEventScheduled = false;
packages/scheduler/src/__tests__/SchedulerDOM-test.js
+1 -1
@@ -83,7 +83,7 @@ describe('SchedulerDOM', () => {
83 this.port1 = port1;
84 this.port2 = port2;
85 };
86 - postMessageCallback = event => port1.onmessage(event);
86 + postMessageCallback = () => port1.onmessage();
87 global.Date.now = function() {
88 return currentTime;
89 };
packages/shared/__tests__/ReactDOMFrameScheduling-test.js
+9 -1
@@ -12,8 +12,15 @@
12 describe('ReactDOMFrameScheduling', () => {
13 it('warns when requestAnimationFrame is not polyfilled in the browser', () => {
14 const previousRAF = global.requestAnimationFrame;
15 + const previousMessageChannel = global.MessageChannel;
16 try {
16 - global.requestAnimationFrame = undefined;
17 + delete global.requestAnimationFrame;
18 + global.MessageChannel = function MessageChannel() {
19 + return {
20 + port1: {},
21 + port2: {},
22 + };
23 + };
24 jest.resetModules();
25 spyOnDevAndProd(console, 'error');
26 require('react-dom');
@@ -22,6 +29,7 @@ describe('ReactDOMFrameScheduling', () => {
29 "This browser doesn't support requestAnimationFrame.",
30 );
31 } finally {
32 + global.MessageChannel = previousMessageChannel;
33 global.requestAnimationFrame = previousRAF;
34 }
35 });