Skip to content

Commit 5d9f64d

Browse files
committed
Solution works in 16.8 also
1 parent 5ef6cb8 commit 5d9f64d

File tree

2 files changed

+79
-15
lines changed

2 files changed

+79
-15
lines changed

src/flush-microtasks.js

+3-15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import scheduleCallback from './scheduler-compat'
2+
13
/* istanbul ignore file */
24
// the part of this file that we need tested is definitely being run
35
// and the part that is not cannot easily have useful tests written
@@ -17,9 +19,6 @@ function getIsUsingFakeTimers() {
1719

1820
let didWarnAboutMessageChannel = false
1921
let enqueueTask
20-
const globalObj = typeof window === 'undefined' ? global : window
21-
22-
let Scheduler = globalObj.Scheduler
2322

2423
try {
2524
// read require off the module object to get around the bundlers.
@@ -29,8 +28,6 @@ try {
2928
// assuming we're in node, let's try to get node's
3029
// version of setImmediate, bypassing fake timers if any.
3130
enqueueTask = nodeRequire.call(module, 'timers').setImmediate
32-
// import React's scheduler so we'll be able to schedule our tasks later on.
33-
Scheduler = nodeRequire.call(module, 'scheduler')
3431
} catch (_err) {
3532
// we're in a browser
3633
// we can't use regular timers because they may still be faked
@@ -55,15 +52,6 @@ try {
5552
}
5653
}
5754

58-
// in case this react version has a Scheduler implementation, we use it,
59-
// if not, we just create a function calling our callback
60-
const scheduleCallback = Scheduler
61-
? Scheduler.scheduleCallback || Scheduler.unstable_scheduleCallback
62-
: (_, cb) => cb()
63-
const NormalPriority = Scheduler
64-
? Scheduler.NormalPriority || Scheduler.unstable_NormalPriority
65-
: null
66-
6755
export default function flushMicroTasks() {
6856
return {
6957
then(resolve) {
@@ -74,7 +62,7 @@ export default function flushMicroTasks() {
7462
jest.advanceTimersByTime(0)
7563
resolve()
7664
} else {
77-
scheduleCallback(NormalPriority, () => {
65+
scheduleCallback(null, () => {
7866
enqueueTask(() => {
7967
resolve()
8068
})

src/scheduler-compat.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const globalObj = typeof window === 'undefined' ? global : window
2+
3+
let Scheduler = globalObj.Scheduler
4+
try {
5+
const requireString = `require${Math.random()}`.slice(0, 7)
6+
const nodeRequire = module && module[requireString]
7+
// import React's scheduler so we'll be able to schedule our tasks later on.
8+
Scheduler = nodeRequire.call(module, 'scheduler')
9+
} catch (_err) {
10+
console.error("The react version you're using doesn't support Scheduling")
11+
}
12+
// in case this react version has a Scheduler implementation, we use it,
13+
// if not, we just create a function calling our callback
14+
const NormalPriority = Scheduler
15+
? Scheduler.NormalPriority || Scheduler.unstable_NormalPriority
16+
: null
17+
18+
const isScheduleCallbackSupported = Scheduler !== undefined
19+
let isModernScheduleCallbackSupported = null
20+
21+
const errorHandler = e => {
22+
// If the error originated from Scheduler, it means we're in v16.8.6
23+
if (
24+
e.message === 'callback is not a function' &&
25+
e.filename.includes('scheduler')
26+
) {
27+
console.error(e.error.stack, e.error.detail)
28+
e.preventDefault()
29+
} else {
30+
console.error(e.error)
31+
}
32+
}
33+
34+
export default function scheduleCallback(_, cb) {
35+
if (!isScheduleCallbackSupported) {
36+
return cb()
37+
}
38+
39+
if (isModernScheduleCallbackSupported === null) {
40+
// patch console.error here
41+
const originalConsoleError = console.error
42+
console.error = function error(...args) {
43+
/* if console.error fired *with that specific message* */
44+
/* istanbul ignore next */
45+
const firstArgIsString = typeof args[0] === 'string'
46+
if (
47+
firstArgIsString &&
48+
args[0].indexOf('TypeError: callback is not a function') === 0
49+
) {
50+
// v16.8.6
51+
isModernScheduleCallbackSupported = false
52+
globalObj.removeEventListener('error', errorHandler)
53+
console.error = originalConsoleError
54+
return cb()
55+
} else {
56+
originalConsoleError.apply(console, args)
57+
console.error = originalConsoleError
58+
return cb()
59+
}
60+
}
61+
62+
globalObj.addEventListener('error', errorHandler)
63+
return Scheduler.unstable_scheduleCallback(NormalPriority, () => {
64+
console.error = originalConsoleError
65+
isModernScheduleCallbackSupported = true
66+
globalObj.removeEventListener('error', errorHandler)
67+
return cb()
68+
})
69+
} else if (isModernScheduleCallbackSupported === false) {
70+
return cb()
71+
}
72+
73+
return Scheduler.unstable_scheduleCallback(NormalPriority, cb)
74+
}
75+
76+
/* eslint no-console:0 */

0 commit comments

Comments
 (0)