From e6304cbbf3c78bf54c7d96fbcd943f72443c52ed Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sat, 10 Feb 2018 11:30:13 -0800 Subject: [PATCH] use event delegation for better perf --- routes/_components/status/Status.html | 20 +++++++++-- routes/_utils/delegate.js | 50 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 routes/_utils/delegate.js diff --git a/routes/_components/status/Status.html b/routes/_components/status/Status.html index 37ac102a..5c3262c3 100644 --- a/routes/_components/status/Status.html +++ b/routes/_components/status/Status.html @@ -1,6 +1,9 @@
{{#if (notification && (notification.type === 'reblog' || notification.type === 'favourite')) || status.reblog}} @@ -87,8 +90,20 @@ import { store } from '../../_store/store' import identity from 'lodash/identity' import { goto } from 'sapper/runtime.js' + import { registerDelegate, unregisterDelegate } from '../../_utils/delegate' export default { + oncreate() { + let delegateKey = this.get('delegateKey') + let onClickOrKeydown = this.onClickOrKeydown.bind(this) + registerDelegate('click', delegateKey, onClickOrKeydown) + registerDelegate('keydown', delegateKey, onClickOrKeydown) + }, + ondestroy() { + let delegateKey = this.get('delegateKey') + unregisterDelegate('click', delegateKey) + unregisterDelegate('keydown', delegateKey) + }, components: { StatusSidebar, StatusHeader, @@ -132,6 +147,7 @@ computed: { originalStatus: (status) => status.reblog ? status.reblog : status, statusId: (originalStatus) => originalStatus.id, + delegateKey: (statusId, timelineType, timelineValue) => `status-${timelineType}-${timelineValue}-${statusId}`, contextualStatusId: ($currentInstance, timelineType, timelineValue, status, notification) => { return `${$currentInstance}/${timelineType}/${timelineValue}/${notification ? notification.id : ''}/${status.id}` }, diff --git a/routes/_utils/delegate.js b/routes/_utils/delegate.js new file mode 100644 index 00000000..d12d2331 --- /dev/null +++ b/routes/_utils/delegate.js @@ -0,0 +1,50 @@ +// Delegate certain events to the global document for perf purposes. + +import { mark, stop } from './marks' + +const callbacks = {} + +if (process.browser && process.env.NODE_ENV !== 'production') { + window.delegateCallbacks = callbacks +} + +function onEvent(e) { + let { type, keyCode, target } = e + if (!(type === 'click' || (type === 'keydown' && keyCode === 13))) { + // we're not interested in any non-click or non-Enter events + return + } + mark('delegate onEvent') + let attr = `delegate-${type}-key` + let key + let element = target + while (element) { + if ((key = element.getAttribute(attr))) { + break + } + element = element.parentElement + } + if (key && callbacks[type] && callbacks[type][key]) { + callbacks[type][key](e) + } + stop('delegate onEvent') +} + +export function registerDelegate(type, key, callback) { + mark('delegate registerDelegate') + callbacks[type] = callbacks[type] || {} + callbacks[type][key] = callback + stop('delegate registerDelegate') +} + +export function unregisterDelegate(type, key) { + mark('delegate unregisterDelegate') + callbacks[type] = callbacks[type] || {} + delete callbacks[type][key] + stop('delegate unregisterDelegate') +} + +if (process.browser) { + document.addEventListener('click', onEvent) + document.addEventListener('keydown', onEvent) +} \ No newline at end of file