1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-10 16:10:55 +00:00

4.0.0-rc18.2

More performance!

* Changed: Push the chat scroll to bottom into a new animation frame to avoid costly recalculations as much as possible.
* Fixed: Runaway performance issue when using FontAwesome icons for in-line chat actions due to an overabundance of CSS.
* Fixed: Emitting updated events for settings that haven't changed, resulting in frequent re-rendering of all chat lines.
This commit is contained in:
SirStendec 2019-04-30 15:18:29 -04:00
parent 918a5fbb13
commit 8bc25b8d5f
7 changed files with 182 additions and 15 deletions

View file

@ -5,10 +5,47 @@
// ============================================================================
import {EventEmitter} from 'utilities/events';
import {has, get as getter, array_equals} from 'utilities/object';
import {has, get as getter, array_equals, set_equals, map_equals, deep_copy} from 'utilities/object';
import * as DEFINITIONS from './types';
/**
* Perform a basic check of a setting's requirements to see if they changed.
* @param {Object} definition
* @param {Map} cache
* @param {Map} old_cache
* @returns Whether or not they changed.
*/
function compare_requirements(definition, cache, old_cache) {
if ( ! definition || ! Array.isArray(definition.requires) )
return false;
for(const req of definition.requires) {
const old_value = old_cache.get(req),
new_value = cache.get(req);
if ( typeof old_value !== typeof new_value )
return true;
if ( Array.isArray(old_value) && Array.isArray(new_value) ) {
if ( ! array_equals(new_value, old_value) )
return true;
} else if ( new_value instanceof Set && old_value instanceof Set ) {
if ( ! set_equals(new_value, old_value) )
return true;
} else if( new_value instanceof Map && old_value instanceof Map ) {
if ( ! map_equals(new_value, old_value) )
return true;
} else if ( new_value !== old_value )
return true;
}
return false;
}
/**
* The SettingsContext class provides a context through which to read
@ -34,6 +71,10 @@ export default class SettingsContext extends EventEmitter {
this.manager.__contexts.push(this);
this._context = context || {};
/*this._context_objects = new Set;
if ( context )
this._updateContext(context, undefined, undefined, new Set);*/
this.__cache = new Map;
this.__meta = new Map;
this.__profiles = [];
@ -125,7 +166,29 @@ export default class SettingsContext extends EventEmitter {
new_uses = new_m ? new_m.uses : null,
old_uses = old_m ? old_m.uses : null;
if ( new_value !== old_value ) {
const definition = this.manager.definitions.get(key);
let changed = false;
if ( definition && definition.equals ) {
if ( definition.equals === 'requirements' )
changed = compare_requirements(definition, this.__cache, old_cache);
else if ( typeof definition.equals === 'function' )
changed = ! definition.equals(new_value, old_value, this.__cache, old_cache);
}
else if ( Array.isArray(new_value) && Array.isArray(old_value) )
changed = ! array_equals(new_value, old_value);
else if ( new_value instanceof Set && old_value instanceof Set )
changed = ! set_equals(new_value, old_value);
else if ( new_value instanceof Map && old_value instanceof Map )
changed = ! map_equals(new_value, old_value);
else if ( new_value !== old_value )
changed = true;
if ( changed ) {
this.emit('changed', key, new_value, old_value);
this.emit(`changed:${key}`, new_value, old_value);
}
@ -161,9 +224,68 @@ export default class SettingsContext extends EventEmitter {
}
/*_updateContext(context, prefix, keys, changed) {
if ( ! context || typeof context !== 'object' )
return;
if ( ! keys )
keys = Object.keys(context);
if ( prefix && this._context_objects.has(prefix) ) {
for(const key of Object.keys(this._context) )
if ( key.startsWith(prefix) ) {
const partial_key = key.substr(prefix.length);
if ( ! keys.includes(partial_key) )
keys.push(partial_key);
}
}
if ( prefix )
this._context_objects.add(prefix);
for(const key of keys) {
const full_key = prefix ? `${prefix}${key}` : key,
pref = `${full_key}.`,
old_value = this._context[full_key],
val = context[key];
const keys = val && (typeof val === 'object') && Object.keys(val);
if ( keys && keys.length ) {
this._updateContext(val, pref, keys, changed);
} else if ( this._context_objects.has(pref) ) {
this._updateContext({}, pref, [], changed);
this._context_objects.delete(pref);
if ( (val || old_value) && val !== old_value ) {
this._context[full_key] = val;
changed.add(full_key);
}
} else if ( val !== old_value ) {
this._context[full_key] = val;
changed.add(full_key);
}
}
}
updateContext(context) {
if ( ! context || typeof context !== 'object' )
return;
const changed = new Set;
this._updateContext(context, undefined, undefined, changed);
if ( changed.size )
this._rebuildContext();
}*/
setContext(context) {
this._context = context;
this._rebuildContext();
this._context_objects = new Set;
this._context = {};
this.updateContext(context);
}
@ -289,6 +411,7 @@ export default class SettingsContext extends EventEmitter {
get(key) {
if ( key.startsWith('context.') )
//return this.__context[key.slice(8)];
return getter(key.slice(8), this.__context);
if ( this.__cache.has(key) )