├── .gitignore ├── Pool.js ├── README.md ├── authors.txt ├── bower.json ├── package.json ├── tests.html └── tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /Pool.js: -------------------------------------------------------------------------------- 1 | function Pool(params) { 2 | if (typeof params !== 'object') { 3 | throw new Error("Please pass parameters. Example -> new Pool({ tagName: \"div\" })"); 4 | } 5 | 6 | if (typeof params.tagName !== 'string') { 7 | throw new Error("Please specify a tagName. Example -> new Pool({ tagName: \"div\" })"); 8 | } 9 | 10 | this.storage = []; 11 | this.tagName = params.tagName.toLowerCase(); 12 | this.namespace = params.namespace; 13 | } 14 | 15 | Pool.prototype.push = function(el) { 16 | if (el.tagName.toLowerCase() !== this.tagName) { 17 | return; 18 | } 19 | 20 | this.storage.push(el); 21 | }; 22 | 23 | Pool.prototype.pop = function(argument) { 24 | if (this.storage.length === 0) { 25 | return this.create(); 26 | } else { 27 | return this.storage.pop(); 28 | } 29 | }; 30 | 31 | Pool.prototype.create = function() { 32 | if (this.namespace) { 33 | return document.createElementNS(this.namespace, this.tagName); 34 | } else { 35 | return document.createElement(this.tagName); 36 | } 37 | }; 38 | 39 | Pool.prototype.allocate = function(size) { 40 | if (this.storage.length >= size) { 41 | return; 42 | } 43 | 44 | var difference = size - this.storage.length; 45 | for (var poolAllocIter = 0; poolAllocIter < difference; poolAllocIter++) { 46 | this.storage.push(this.create()); 47 | } 48 | }; 49 | 50 | if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 51 | module.exports = Pool; 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dom-pool 2 | ======== 3 | 4 | Let your app focus on rendering 60fps. Avoid creating & GC'ing DOM nodes on the fly. 5 | 6 | ### Installation 7 | ```bash 8 | npm install dom-pool --save 9 | ``` 10 | 11 | ### Usage 12 | ```js 13 | // Grab the library from NPM or Bower. 14 | const Pool = require('dom-pool'); 15 | 16 | // Create a new Pool for a specific DOM tagName, like "div". 17 | const divPool = new Pool({ 18 | tagName: 'div' 19 | }); 20 | 21 | // Pools have an Array-like syntax: "pop" & "push". 22 | const div = divPool.pop(); 23 | 24 | // ... let's imagine doing awesome stuff with the DIV ... 25 | 26 | // Once you're done with the DIV, return it to the Pool with "push". 27 | divPool.push(div); 28 | 29 | // Next time "pop" is called, your app can efficiently reuse the DIV. 30 | 31 | // To create DIVs ahead of time, use the "allocate" method. 32 | divPool.allocate(100); 33 | ``` 34 | 35 | ### Custom namespaces 36 | ```js 37 | // SVG is also supported. 38 | // We just need to specify its namespace. 39 | const circlePool = new Pool({ 40 | namespace: 'http://www.w3.org/2000/svg', 41 | tagName: 'circle' 42 | }); 43 | 44 | // Let's allocate 128 circles. 45 | circlePool.allocate(128); 46 | ``` 47 | 48 | ### What performance gains can I expect? 49 | Reusing DOM elements is [2-6 times faster](http://jsperf.com/dom-pool-performance-1) than creating DOM elements. 50 | 51 | ![Performance](https://i.imgur.com/VaUcUQy.png) 52 | 53 | Now is this performance totally free? Not exactly. When you create a DOM element, it's like a blank slate. When you reuse a DOM element, it keeps the attributes you've given it. However, if you're going to be updating those same attributes anyways, it's basically free. 54 | 55 | ### What browsers are supported? 56 | Modern browsers & IE9+. If you're sticking to HTML nodes then IE5+ is supported. The reason being, IE added support for [createElementNS](http://msdn.microsoft.com/en-us/library/ie/ff975213%28v=vs.85%29.aspx) in version 9. 57 | 58 | ### Screenshots of dom-pool in use, with Chrome DevTools 59 | 60 | Note the DOM node count over time. 61 | 62 | ![Pooling DOM nodes](https://i.imgur.com/gzkbN1X.png) 63 | 64 | ![Creating DOM nodes](https://i.imgur.com/oEJyNO7.png) 65 | -------------------------------------------------------------------------------- /authors.txt: -------------------------------------------------------------------------------- 1 | Authors ordered by first contribution. 2 | 3 | Chris Antaki 4 | Matthew Vita 5 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dom-pool", 3 | "version": "0.1.0", 4 | "homepage": "https://github.com/ChrisAntaki/dom-pool", 5 | "authors": [ 6 | "Chris Antaki " 7 | ], 8 | "description": "Make your browser's life easier", 9 | "main": "Pool.js", 10 | "moduleType": [ 11 | "globals", 12 | "node" 13 | ], 14 | "keywords": [ 15 | "dom", 16 | "pool" 17 | ], 18 | "license": "ISC", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dom-pool", 3 | "version": "0.1.1", 4 | "description": "Make your browser's life easier", 5 | "main": "Pool.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/ChrisAntaki/dom-pool.git" 12 | }, 13 | "keywords": [ 14 | "dom", 15 | "pool" 16 | ], 17 | "author": "Chris Antaki", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/ChrisAntaki/dom-pool/issues" 21 | }, 22 | "homepage": "https://github.com/ChrisAntaki/dom-pool" 23 | } 24 | -------------------------------------------------------------------------------- /tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Example 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests.js: -------------------------------------------------------------------------------- 1 | QUnit.test( 2 | "dom-pool", 3 | function(assert) { 4 | assert.ok( 5 | typeof Pool !== "undefined", 6 | "Global definition in the absence of CommonJS support" 7 | ); 8 | 9 | assert.throws( 10 | function() { 11 | new Pool; 12 | }, 13 | /pass parameters/, 14 | "Parameters are required" 15 | ); 16 | 17 | assert.throws( 18 | function() { 19 | new Pool({}); 20 | }, 21 | /specify a tagName/, 22 | "tagName parameter is required" 23 | ); 24 | 25 | var divPool = new Pool({ 26 | tagName: "div" 27 | }); 28 | assert.ok( 29 | divPool, 30 | "Creating a div pool" 31 | ); 32 | 33 | var element = divPool.pop(); 34 | assert.ok( 35 | ( 36 | element 37 | && 38 | element.tagName === 'DIV' 39 | && 40 | divPool.storage.length === 0 41 | ), 42 | "pop()" 43 | ); 44 | 45 | divPool.push(element); 46 | assert.ok( 47 | ( 48 | divPool.storage[0] === element 49 | && 50 | divPool.storage.length === 1 51 | ), 52 | "push(element)" 53 | ); 54 | 55 | divPool.allocate(100); 56 | assert.ok( 57 | ( 58 | divPool.storage.length === 100 59 | ), 60 | "allocate(100)" 61 | ); 62 | 63 | var circlePool = new Pool({ 64 | namespace: 'http://www.w3.org/2000/svg', 65 | tagName: "circle" 66 | }); 67 | assert.ok( 68 | circlePool, 69 | "Creating a circle pool (in the SVG namespace)" 70 | ); 71 | 72 | var circle = circlePool.pop(); 73 | assert.ok( 74 | ( 75 | circle 76 | && 77 | circle.tagName === 'circle' 78 | && 79 | circlePool.storage.length === 0 80 | ), 81 | "pop()" 82 | ); 83 | 84 | circlePool.push(circle); 85 | assert.ok( 86 | ( 87 | circlePool.storage[0] === circle 88 | && 89 | circlePool.storage.length === 1 90 | ), 91 | "push(circle)" 92 | ); 93 | 94 | circlePool.allocate(100); 95 | assert.ok( 96 | ( 97 | circlePool.storage.length === 100 98 | ), 99 | "allocate(100)" 100 | ); 101 | } 102 | ); 103 | --------------------------------------------------------------------------------