diff --git a/packages/diffhtml/lib/util/memory.js b/packages/diffhtml/lib/util/memory.js index 69bc7085..9cc98aaa 100644 --- a/packages/diffhtml/lib/util/memory.js +++ b/packages/diffhtml/lib/util/memory.js @@ -1,5 +1,5 @@ import Pool from './pool'; -import { NodeCache } from './types'; +import { EMPTY, NodeCache } from './types'; const { protect, unprotect, memory } = Pool; @@ -56,6 +56,7 @@ export function gc() { // Scrub a VTree of attributes and childNodes to avoid ever increasing RAM. vTree.attributes = {}; vTree.childNodes.length = 0; + vTree.key = EMPTY.STR; // Make the VTree available for future renders. memory.free.add(vTree); diff --git a/packages/diffhtml/lib/util/pool.js b/packages/diffhtml/lib/util/pool.js index 088b35f3..9fdd6713 100644 --- a/packages/diffhtml/lib/util/pool.js +++ b/packages/diffhtml/lib/util/pool.js @@ -53,6 +53,10 @@ const Pool = { }, /** + * + * Moves a VTree from the "free" state to the "allocated" state. If the pool + * is empty, it creates a new object. + * * @return {VTree} */ get() { @@ -72,6 +76,9 @@ const Pool = { }, /** + * Moves a VTree from "allocated" state to "protected" state. This means that + * the VTrees will persist between transactions. + * * @param {VTree} vTree - Virtual Tree to protect */ protect(vTree) { @@ -80,13 +87,15 @@ const Pool = { }, /** + * Moves a VTree from "protected" state to "allocated" state. They will be + * brought back into "free" circulation during a GC. + * * @param {VTree} vTree - Virtual Tree to unprotect and deallocate */ unprotect(vTree) { if (protect.has(vTree) || allocate.has(vTree)) { protect.delete(vTree); - allocate.delete(vTree); - free.add(vTree); + allocate.add(vTree); } }, }; diff --git a/packages/diffhtml/test/util.js b/packages/diffhtml/test/util.js index c22e0a8a..2995103e 100644 --- a/packages/diffhtml/test/util.js +++ b/packages/diffhtml/test/util.js @@ -1166,6 +1166,51 @@ describe('Util', () => { strictEqual(Pool.memory.protected.size, 0); }); + it('will only reset attributes once garbage collected', () => { + const expected = 'somestr'; + const vTree = createTree('div', { someAttr: expected }); + + protectVTree(vTree); + strictEqual(vTree.attributes.someAttr, expected); + + unprotectVTree(vTree); + strictEqual(vTree.attributes.someAttr, expected); + + gc(); + + strictEqual(vTree.attributes.someAttr, undefined); + }); + + it('will only reset childNodes once garbage collected', () => { + const expected = 'somestr'; + const vTree = createTree('div', null, createTree('span')); + + protectVTree(vTree); + strictEqual(vTree.childNodes.length, 1); + + unprotectVTree(vTree); + strictEqual(vTree.childNodes.length, 1); + + gc(); + + strictEqual(vTree.childNodes.length, 0); + }); + + it('will only reset key once garbage collected', () => { + const expected = 'somestr'; + const vTree = createTree('div', { key: expected }); + + protectVTree(vTree); + strictEqual(vTree.key, expected); + + unprotectVTree(vTree); + strictEqual(vTree.key, expected); + + gc(); + + strictEqual(vTree.key, ''); + }); + it('will garbage collect DOM Node associations', () => { const domNode = document.createElement('div'); const vTree = createTree(domNode);