mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-03 14:37:02 +03:00
Tiny knockoutjs speedup
This commit is contained in:
parent
8aa9b0b33f
commit
c3c1fc2c0e
5 changed files with 165 additions and 208 deletions
|
|
@ -12,7 +12,6 @@ ko.bindingHandlers['textInput'] = {
|
|||
var elementValue = element.value;
|
||||
if (previousElementValue !== elementValue) {
|
||||
// Provide a way for tests to know exactly which event was processed
|
||||
if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;
|
||||
previousElementValue = elementValue;
|
||||
ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);
|
||||
}
|
||||
|
|
@ -25,8 +24,7 @@ ko.bindingHandlers['textInput'] = {
|
|||
// updates that are from the previous state of the element, usually due to techniques
|
||||
// such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.
|
||||
elementValueBeforeEvent = element.value;
|
||||
var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;
|
||||
timeoutHandle = ko.utils.setTimeout(handler, 4);
|
||||
timeoutHandle = ko.utils.setTimeout(updateModel, 4);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -53,18 +51,7 @@ ko.bindingHandlers['textInput'] = {
|
|||
var onEvent = (event, handler) =>
|
||||
ko.utils.registerEventHandler(element, event, handler);
|
||||
|
||||
if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {
|
||||
// Provide a way for tests to specify exactly which events are bound
|
||||
ko.bindingHandlers['textInput']['_forceUpdateOn'].forEach(eventName => {
|
||||
if (eventName.slice(0,5) == 'after') {
|
||||
onEvent(eventName.slice(5), deferUpdateModel);
|
||||
} else {
|
||||
onEvent(eventName, updateModel);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
onEvent('input', updateModel);
|
||||
}
|
||||
onEvent('input', updateModel);
|
||||
|
||||
// Bind to the change event so that we can catch programmatic updates of the value that fire this event.
|
||||
onEvent('change', updateModel);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
var computedState = Symbol('_state');
|
||||
|
||||
ko.computed = function (evaluatorFunctionOrOptions, options) {
|
||||
ko.computed = (evaluatorFunctionOrOptions, options) => {
|
||||
if (typeof evaluatorFunctionOrOptions === "object") {
|
||||
// Single-parameter syntax - everything is on this "options" param
|
||||
options = evaluatorFunctionOrOptions;
|
||||
|
|
@ -71,11 +71,6 @@ ko.computed = function (evaluatorFunctionOrOptions, options) {
|
|||
ko.utils.extend(computedObservable, deferEvaluationOverrides);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
// #1731 - Aid debugging by exposing the computed's options
|
||||
computedObservable["_options"] = options;
|
||||
}
|
||||
|
||||
if (state.disposeWhenNodeIsRemoved) {
|
||||
// Since this computed is associated with a DOM node, and we don't want to dispose the computed
|
||||
// until the DOM node is *removed* from the document (as opposed to never having been in the document),
|
||||
|
|
@ -99,7 +94,7 @@ ko.computed = function (evaluatorFunctionOrOptions, options) {
|
|||
// Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is
|
||||
// removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).
|
||||
if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {
|
||||
ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {
|
||||
ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = () => {
|
||||
computedObservable.dispose();
|
||||
});
|
||||
}
|
||||
|
|
@ -136,6 +131,26 @@ function computedBeginDependencyDetectionCallback(subscribable, id) {
|
|||
}
|
||||
}
|
||||
|
||||
function evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext) {
|
||||
// This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.
|
||||
// You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection
|
||||
// can be independent of try/finally blocks, which contributes to saving about 40% off the CPU
|
||||
// overhead of computed evaluation (on V8 at least).
|
||||
|
||||
try {
|
||||
return state.readFunction();
|
||||
} finally {
|
||||
ko.dependencyDetection.end();
|
||||
|
||||
// For each subscription no longer being used, remove it from the active subscriptions list and dispose it
|
||||
if (dependencyDetectionContext.disposalCount && !state.isSleeping) {
|
||||
ko.utils.objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);
|
||||
}
|
||||
|
||||
state.isStale = state.isDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
var computedFn = {
|
||||
"equalityComparer": valuesArePrimitiveAndEqual,
|
||||
getDependenciesCount: function () {
|
||||
|
|
@ -284,7 +299,7 @@ var computedFn = {
|
|||
state.dependencyTracking = {};
|
||||
state.dependenciesCount = 0;
|
||||
|
||||
var newValue = this.evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);
|
||||
var newValue = evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);
|
||||
|
||||
if (!state.dependenciesCount) {
|
||||
computedObservable.dispose();
|
||||
|
|
@ -301,7 +316,6 @@ var computedFn = {
|
|||
}
|
||||
|
||||
state.latestValue = newValue;
|
||||
if (DEBUG) computedObservable._latestValue = newValue;
|
||||
|
||||
computedObservable["notifySubscribers"](state.latestValue, "spectate");
|
||||
|
||||
|
|
@ -319,25 +333,6 @@ var computedFn = {
|
|||
|
||||
return changed;
|
||||
},
|
||||
evaluateImmediate_CallReadThenEndDependencyDetection: (state, dependencyDetectionContext) => {
|
||||
// This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.
|
||||
// You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection
|
||||
// can be independent of try/finally blocks, which contributes to saving about 40% off the CPU
|
||||
// overhead of computed evaluation (on V8 at least).
|
||||
|
||||
try {
|
||||
return state.readFunction();
|
||||
} finally {
|
||||
ko.dependencyDetection.end();
|
||||
|
||||
// For each subscription no longer being used, remove it from the active subscriptions list and dispose it
|
||||
if (dependencyDetectionContext.disposalCount && !state.isSleeping) {
|
||||
ko.utils.objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);
|
||||
}
|
||||
|
||||
state.isStale = state.isDirty = false;
|
||||
}
|
||||
},
|
||||
peek: function (evaluate) {
|
||||
// By default, peek won't re-evaluate, except while the computed is sleeping or to get the initial value when "deferEvaluation" is set.
|
||||
// Pass in true to evaluate if needed.
|
||||
|
|
|
|||
45
vendors/knockout/src/utils.domNodeDisposal.js
vendored
45
vendors/knockout/src/utils.domNodeDisposal.js
vendored
|
|
@ -1,24 +1,23 @@
|
|||
|
||||
ko.utils.domNodeDisposal = new (function () {
|
||||
ko.utils.domNodeDisposal = (() => {
|
||||
var domDataKey = ko.utils.domData.nextKey();
|
||||
var cleanableNodeTypes = { 1: true, 8: true, 9: true }; // Element, Comment, Document
|
||||
var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
|
||||
var cleanableNodeTypes = { 1: 1, 8: 1, 9: 1 }; // Element, Comment, Document
|
||||
var cleanableNodeTypesWithDescendants = { 1: 1, 9: 1 }; // Element, Document
|
||||
|
||||
function getDisposeCallbacksCollection(node, createIfNotFound) {
|
||||
const getDisposeCallbacksCollection = (node, createIfNotFound) => {
|
||||
var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
|
||||
if ((allDisposeCallbacks === undefined) && createIfNotFound) {
|
||||
allDisposeCallbacks = [];
|
||||
ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
|
||||
}
|
||||
return allDisposeCallbacks;
|
||||
}
|
||||
function destroyCallbacksCollection(node) {
|
||||
ko.utils.domData.set(node, domDataKey, undefined);
|
||||
}
|
||||
},
|
||||
|
||||
function cleanSingleNode(node) {
|
||||
destroyCallbacksCollection = node => ko.utils.domData.set(node, domDataKey, undefined),
|
||||
|
||||
cleanSingleNode = node => {
|
||||
// Run all the dispose callbacks
|
||||
var callbacks = getDisposeCallbacksCollection(node, false);
|
||||
var callbacks = getDisposeCallbacksCollection(node);
|
||||
if (callbacks) {
|
||||
callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
|
||||
for (var i = 0; i < callbacks.length; i++)
|
||||
|
|
@ -30,12 +29,11 @@ ko.utils.domNodeDisposal = new (function () {
|
|||
|
||||
// Clear any immediate-child comment nodes, as these wouldn't have been found by
|
||||
// node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
|
||||
if (cleanableNodeTypesWithDescendants[node.nodeType]) {
|
||||
cleanNodesInList(node.childNodes, true/*onlyComments*/);
|
||||
}
|
||||
}
|
||||
cleanableNodeTypesWithDescendants[node.nodeType]
|
||||
&& cleanNodesInList(node.childNodes, true/*onlyComments*/);
|
||||
},
|
||||
|
||||
function cleanNodesInList(nodeList, onlyComments) {
|
||||
cleanNodesInList = (nodeList, onlyComments) => {
|
||||
var cleanedNodes = [], lastCleanedNode;
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
if (!onlyComments || nodeList[i].nodeType === 8) {
|
||||
|
|
@ -45,21 +43,20 @@ ko.utils.domNodeDisposal = new (function () {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
addDisposeCallback : (node, callback) => {
|
||||
if (typeof callback != "function")
|
||||
throw new Error("Callback must be a function");
|
||||
getDisposeCallbacksCollection(node, true).push(callback);
|
||||
getDisposeCallbacksCollection(node, 1).push(callback);
|
||||
},
|
||||
|
||||
removeDisposeCallback : (node, callback) => {
|
||||
var callbacksCollection = getDisposeCallbacksCollection(node, false);
|
||||
var callbacksCollection = getDisposeCallbacksCollection(node);
|
||||
if (callbacksCollection) {
|
||||
ko.utils.arrayRemoveItem(callbacksCollection, callback);
|
||||
if (callbacksCollection.length == 0)
|
||||
destroyCallbacksCollection(node);
|
||||
callbacksCollection.length || destroyCallbacksCollection(node);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -70,9 +67,8 @@ ko.utils.domNodeDisposal = new (function () {
|
|||
cleanSingleNode(node);
|
||||
|
||||
// ... then its descendants, where applicable
|
||||
if (cleanableNodeTypesWithDescendants[node.nodeType]) {
|
||||
cleanNodesInList(node.getElementsByTagName("*"));
|
||||
}
|
||||
cleanableNodeTypesWithDescendants[node.nodeType]
|
||||
&& cleanNodesInList(node.getElementsByTagName("*"));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -81,8 +77,7 @@ ko.utils.domNodeDisposal = new (function () {
|
|||
|
||||
removeNode : node => {
|
||||
ko.cleanNode(node);
|
||||
if (node.parentNode)
|
||||
node.parentNode.removeChild(node);
|
||||
node.parentNode && node.parentNode.removeChild(node);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue