Precise DOM morphing
morphing typescript dom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Speed up ID map traversal with TreeWalker

Replace querySelectorAll("[id]") scans in ID mapping with a TreeWalker-based descendant pass to reduce selector overhead in hot morph paths while keeping matching behavior unchanged.

+22 -6
+22 -6
src/morphlex.ts
··· 1 1 const SUPPORTS_MOVE_BEFORE = "moveBefore" in Element.prototype 2 2 const ELEMENT_NODE_TYPE = 1 3 3 const TEXT_NODE_TYPE = 3 4 + const TREE_WALKER_SHOW_ELEMENT = 1 4 5 5 6 const IS_PARENT_NODE_TYPE = [ 6 7 0, // 0: (unused) ··· 804 805 #mapIdArrays(node: ParentNode): void { 805 806 const idArrayMap = this.#idArrayMap 806 807 807 - for (const element of node.querySelectorAll("[id]")) { 808 + forEachDescendantElementWithId(node, (element) => { 808 809 const id = element.id 809 810 810 - if (id === "") continue 811 + if (id === "") return 811 812 812 813 let currentElement: Element | null = element 813 814 ··· 821 822 if (currentElement === node) break 822 823 currentElement = currentElement.parentElement 823 824 } 824 - } 825 + }) 825 826 } 826 827 827 828 // For each node with an ID, add that ID into the IdSet on the IdSetMap, for each of its parent elements. 828 829 #mapIdSets(node: ParentNode): void { 829 830 const idSetMap = this.#idSetMap 830 831 831 - for (const element of node.querySelectorAll("[id]")) { 832 + forEachDescendantElementWithId(node, (element) => { 832 833 const id = element.id 833 834 834 - if (id === "") continue 835 + if (id === "") return 835 836 836 837 let currentElement: Element | null = element 837 838 ··· 845 846 if (currentElement === node) break 846 847 currentElement = currentElement.parentElement 847 848 } 848 - } 849 + }) 849 850 } 850 851 } 851 852 ··· 883 884 } 884 885 885 886 new Morph(flushOptions, null, from).morph(from as ChildNode, to) 887 + } 888 + 889 + function forEachDescendantElementWithId(node: ParentNode, callback: (element: Element) => void): void { 890 + const root = node as Node 891 + const ownerDocument = root.nodeType === 9 ? (root as Document) : root.ownerDocument 892 + if (!ownerDocument) return 893 + 894 + const walker = ownerDocument.createTreeWalker(root, TREE_WALKER_SHOW_ELEMENT) 895 + let current = walker.nextNode() 896 + 897 + while (current) { 898 + const element = current as Element 899 + if (element.id !== "") callback(element) 900 + current = walker.nextNode() 901 + } 886 902 } 887 903 888 904 function nodeListToArray(nodeList: NodeListOf<ChildNode>): Array<ChildNode>