mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-30 20:49:20 +03:00
Speedup Knockout a bit
This commit is contained in:
parent
24681f8955
commit
8a461e7a3d
4 changed files with 164 additions and 200 deletions
|
|
@ -120,14 +120,14 @@ ko.bindingContext = class {
|
|||
}
|
||||
};
|
||||
|
||||
function asyncContextDispose(node) {
|
||||
const asyncContextDispose = node => {
|
||||
var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey),
|
||||
asyncContext = bindingInfo?.asyncContext;
|
||||
if (asyncContext) {
|
||||
bindingInfo.asyncContext = null;
|
||||
asyncContext.notifyAncestor();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AsyncCompleteContext {
|
||||
constructor(node, bindingInfo, ancestorBindingInfo) {
|
||||
|
|
@ -211,7 +211,7 @@ ko.bindingEvent = {
|
|||
}
|
||||
};
|
||||
|
||||
function applyBindingsToDescendantsInternal(bindingContext, elementOrVirtualElement) {
|
||||
const applyBindingsToDescendantsInternal = (bindingContext, elementOrVirtualElement) => {
|
||||
var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
|
||||
|
||||
while (currentChild = nextInQueue) {
|
||||
|
|
@ -220,17 +220,15 @@ function applyBindingsToDescendantsInternal(bindingContext, elementOrVirtualElem
|
|||
applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild);
|
||||
}
|
||||
ko.bindingEvent.notify(elementOrVirtualElement, ko.bindingEvent.childrenComplete);
|
||||
}
|
||||
};
|
||||
|
||||
function applyBindingsToNodeAndDescendantsInternal(bindingContext, nodeVerified) {
|
||||
const applyBindingsToNodeAndDescendantsInternal = (bindingContext, nodeVerified) => {
|
||||
var bindingContextForDescendants = bindingContext;
|
||||
|
||||
var isElement = (nodeVerified.nodeType === 1);
|
||||
|
||||
// Perf optimisation: Apply bindings only if...
|
||||
// (1) We need to store the binding info for the node (all element nodes)
|
||||
// (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
|
||||
if (isElement || ko.bindingProvider.nodeHasBindings(nodeVerified))
|
||||
if ((1 === nodeVerified.nodeType) || ko.bindingProvider.nodeHasBindings(nodeVerified))
|
||||
bindingContextForDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext);
|
||||
|
||||
// Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,
|
||||
|
|
@ -241,41 +239,42 @@ function applyBindingsToNodeAndDescendantsInternal(bindingContext, nodeVerified)
|
|||
if (bindingContextForDescendants && !nodeVerified.matches?.('SCRIPT,TEXTAREA,TEMPLATE')) {
|
||||
applyBindingsToDescendantsInternal(bindingContextForDescendants, nodeVerified);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function topologicalSortBindings(bindings) {
|
||||
const topologicalSortBindings = bindings => {
|
||||
// Depth-first sort
|
||||
var result = [], // The list of key/handler pairs that we will return
|
||||
bindingsConsidered = {}, // A temporary record of which bindings are already in 'result'
|
||||
cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
|
||||
ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {
|
||||
if (!bindingsConsidered[bindingKey]) {
|
||||
var binding = ko.bindingHandlers[bindingKey];
|
||||
if (binding) {
|
||||
// First add dependencies (if any) of the current binding
|
||||
if (binding['after']) {
|
||||
cyclicDependencyStack.push(bindingKey);
|
||||
binding['after'].forEach(bindingDependencyKey => {
|
||||
if (bindings[bindingDependencyKey]) {
|
||||
if (cyclicDependencyStack.includes(bindingDependencyKey)) {
|
||||
throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
|
||||
cyclicDependencyStack = [], // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
|
||||
pushBinding = bindingKey => {
|
||||
if (!bindingsConsidered[bindingKey]) {
|
||||
var binding = ko.bindingHandlers[bindingKey];
|
||||
if (binding) {
|
||||
// First add dependencies (if any) of the current binding
|
||||
if (binding['after']) {
|
||||
cyclicDependencyStack.push(bindingKey);
|
||||
binding['after'].forEach(bindingDependencyKey => {
|
||||
if (bindings[bindingDependencyKey]) {
|
||||
if (cyclicDependencyStack.includes(bindingDependencyKey)) {
|
||||
throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
|
||||
}
|
||||
pushBinding(bindingDependencyKey);
|
||||
}
|
||||
pushBinding(bindingDependencyKey);
|
||||
}
|
||||
});
|
||||
cyclicDependencyStack.length--;
|
||||
});
|
||||
cyclicDependencyStack.length--;
|
||||
}
|
||||
// Next add the current binding
|
||||
result.push({ key: bindingKey, handler: binding });
|
||||
}
|
||||
// Next add the current binding
|
||||
result.push({ key: bindingKey, handler: binding });
|
||||
bindingsConsidered[bindingKey] = true;
|
||||
}
|
||||
bindingsConsidered[bindingKey] = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
ko.utils.objectForEach(bindings, pushBinding);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
function applyBindingsToNodeInternal(node, sourceBindings, bindingContext) {
|
||||
const applyBindingsToNodeInternal = (node, sourceBindings, bindingContext) => {
|
||||
var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});
|
||||
|
||||
// Prevent multiple applyBindings calls for the same node, except when a binding value is specified
|
||||
|
|
@ -294,13 +293,13 @@ function applyBindingsToNodeInternal(node, sourceBindings, bindingContext) {
|
|||
}
|
||||
|
||||
// Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings
|
||||
var bindings;
|
||||
var bindings, bindingsUpdater;
|
||||
if (sourceBindings && typeof sourceBindings !== 'function') {
|
||||
bindings = sourceBindings;
|
||||
} else {
|
||||
// Get the binding from the provider within a computed observable so that we can update the bindings whenever
|
||||
// the binding context is updated or if the binding provider accesses observables.
|
||||
var bindingsUpdater = ko.computed(
|
||||
bindingsUpdater = ko.computed(
|
||||
() => {
|
||||
bindings = sourceBindings ? sourceBindings(bindingContext, node) : ko.bindingProvider.getBindingAccessors(node, bindingContext);
|
||||
// Register a dependency on the binding context to support observable view models.
|
||||
|
|
@ -398,46 +397,30 @@ function applyBindingsToNodeInternal(node, sourceBindings, bindingContext) {
|
|||
}
|
||||
|
||||
return bindingHandlerThatControlsDescendantBindings === undefined && contextToExtend;
|
||||
}
|
||||
};
|
||||
|
||||
ko.storedBindingContextForNode = node => {
|
||||
var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);
|
||||
return bindingInfo && bindingInfo.context;
|
||||
}
|
||||
ko.storedBindingContextForNode = node =>
|
||||
ko.utils.domData.get(node, boundElementDomDataKey)?.context;
|
||||
|
||||
function getBindingContext(viewModelOrBindingContext, extendContextCallback) {
|
||||
return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
|
||||
const getBindingContext = (viewModelOrBindingContext) =>
|
||||
viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
|
||||
? viewModelOrBindingContext
|
||||
: new ko.bindingContext(viewModelOrBindingContext, null, extendContextCallback);
|
||||
}
|
||||
: new ko.bindingContext(viewModelOrBindingContext);
|
||||
|
||||
ko['applyBindingAccessorsToNode'] = (node, bindings, viewModelOrBindingContext) =>
|
||||
applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext));
|
||||
|
||||
ko.applyBindingsToDescendants = (viewModelOrBindingContext, rootNode) => {
|
||||
if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
|
||||
applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode);
|
||||
};
|
||||
ko.applyBindingsToDescendants = (viewModelOrBindingContext, rootNode) =>
|
||||
(rootNode.nodeType === 1 || rootNode.nodeType === 8)
|
||||
&& applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode);
|
||||
|
||||
ko.applyBindings = function (viewModelOrBindingContext, rootNode, extendContextCallback) {
|
||||
if (arguments.length < 2) {
|
||||
rootNode = document.body;
|
||||
if (!rootNode) {
|
||||
throw Error("ko.applyBindings: could not find document.body; has the document been loaded?");
|
||||
}
|
||||
} else if (!rootNode || (rootNode.nodeType !== 1 && rootNode.nodeType !== 8)) {
|
||||
throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
|
||||
}
|
||||
|
||||
applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext, extendContextCallback), rootNode);
|
||||
};
|
||||
ko.applyBindings = (viewModelOrBindingContext, rootNode) =>
|
||||
applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode);
|
||||
|
||||
// Retrieving binding context from arbitrary nodes
|
||||
ko['dataFor'] = node => {
|
||||
ko['dataFor'] = node =>
|
||||
// We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
|
||||
var context = node && [1,8].includes(node.nodeType) && ko.storedBindingContextForNode(node);
|
||||
return context ? context['$data'] : undefined;
|
||||
};
|
||||
([1,8].includes(node?.nodeType) && ko.storedBindingContextForNode(node))?.['$data'];
|
||||
|
||||
ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
|
||||
ko.exportSymbol('applyBindings', ko.applyBindings);
|
||||
//ko.exportSymbol('applyBindings', ko.applyBindings);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue