fix(runtime-dom): fix event listeners call in firefox <= 53 (#3501)

fix #3485
This commit is contained in:
HcySunYang 2021-03-30 07:15:12 +08:00 committed by GitHub
parent 42b68c773d
commit 33ba0e3229
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -15,19 +15,24 @@ type EventValue = Function | Function[]
// Async edge case fix requires storing an event listener's attach timestamp. // Async edge case fix requires storing an event listener's attach timestamp.
let _getNow: () => number = Date.now let _getNow: () => number = Date.now
let skipTimestampCheck = false
if (typeof window !== 'undefined') {
// Determine what event timestamp the browser is using. Annoyingly, the // Determine what event timestamp the browser is using. Annoyingly, the
// timestamp can either be hi-res (relative to page load) or low-res // timestamp can either be hi-res (relative to page load) or low-res
// (relative to UNIX epoch), so in order to compare time we have to use the // (relative to UNIX epoch), so in order to compare time we have to use the
// same timestamp type when saving the flush timestamp. // same timestamp type when saving the flush timestamp.
if ( if (_getNow() > document.createEvent('Event').timeStamp) {
typeof document !== 'undefined' &&
_getNow() > document.createEvent('Event').timeStamp
) {
// if the low-res timestamp which is bigger than the event timestamp // if the low-res timestamp which is bigger than the event timestamp
// (which is evaluated AFTER) it means the event is using a hi-res timestamp, // (which is evaluated AFTER) it means the event is using a hi-res timestamp,
// and we need to use the hi-res version for event listeners as well. // and we need to use the hi-res version for event listeners as well.
_getNow = () => performance.now() _getNow = () => performance.now()
} }
// #3485: Firefox <= 53 has incorrect Event.timeStamp implementation
// and does not fire microtasks in between event propagation, so safe to exclude.
const ffMatch = navigator.userAgent.match(/firefox\/(\d+)/i)
skipTimestampCheck = !!(ffMatch && Number(ffMatch[1]) <= 53)
}
// To avoid the overhead of repeatedly calling performance.now(), we cache // To avoid the overhead of repeatedly calling performance.now(), we cache
// and use the same timestamp for all event listeners attached in the same tick. // and use the same timestamp for all event listeners attached in the same tick.
@ -111,7 +116,8 @@ function createInvoker(
// and the handler would only fire if the event passed to it was fired // and the handler would only fire if the event passed to it was fired
// AFTER it was attached. // AFTER it was attached.
const timeStamp = e.timeStamp || _getNow() const timeStamp = e.timeStamp || _getNow()
if (timeStamp >= invoker.attached - 1) {
if (skipTimestampCheck || timeStamp >= invoker.attached - 1) {
callWithAsyncErrorHandling( callWithAsyncErrorHandling(
patchStopImmediatePropagation(e, invoker.value), patchStopImmediatePropagation(e, invoker.value),
instance, instance,