diff options
Diffstat (limited to 'thirdparty/preact/test/browser/performance.js')
-rw-r--r-- | thirdparty/preact/test/browser/performance.js | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/thirdparty/preact/test/browser/performance.js b/thirdparty/preact/test/browser/performance.js new file mode 100644 index 000000000..e1f7d7956 --- /dev/null +++ b/thirdparty/preact/test/browser/performance.js @@ -0,0 +1,245 @@ +/*global coverage, ENABLE_PERFORMANCE, NODE_ENV*/ +/*eslint no-console:0*/ +/** @jsx h */ + +let { h, Component, render } = require(NODE_ENV==='production' ? '../../dist/preact.min.js' : '../../src/preact'); + +const MULTIPLIER = ENABLE_PERFORMANCE ? (coverage ? 5 : 1) : 999999; + + +let now = typeof performance!=='undefined' && performance.now ? () => performance.now() : () => +new Date(); + +function loop(iter, time) { + let start = now(), + count = 0; + while ( now()-start < time ) { + count++; + iter(); + } + return count; +} + + +function benchmark(iter, callback) { + let a = 0; + function noop() { + try { a++; } finally { a += Math.random(); } + } + + // warm + for (let i=3; i--; ) noop(), iter(); + + let count = 5, + time = 200, + passes = 0, + noops = loop(noop, time), + iterations = 0; + + function next() { + iterations += loop(iter, time); + setTimeout(++passes===count ? done : next, 10); + } + + function done() { + let ticks = Math.round(noops / iterations * count), + hz = iterations / count / time * 1000, + message = `${hz|0}/s (${ticks} ticks)`; + callback({ iterations, noops, count, time, ticks, hz, message }); + } + + next(); +} + + +describe('performance', function() { + let scratch; + + this.timeout(10000); + + before( () => { + if (coverage) { + console.warn('WARNING: Code coverage is enabled, which dramatically reduces performance. Do not pay attention to these numbers.'); + } + scratch = document.createElement('div'); + (document.body || document.documentElement).appendChild(scratch); + }); + + beforeEach( () => { + scratch.innerHTML = ''; + }); + + after( () => { + scratch.parentNode.removeChild(scratch); + scratch = null; + }); + + it('should rerender without changes fast', done => { + let jsx = ( + <div class="foo bar" data-foo="bar" p={2}> + <header> + <h1 class="asdf">a {'b'} c {0} d</h1> + <nav> + <a href="/foo">Foo</a> + <a href="/bar">Bar</a> + </nav> + </header> + <main> + <form onSubmit={()=>{}}> + <input type="checkbox" checked={true} /> + <input type="checkbox" checked={false} /> + <fieldset> + <label><input type="radio" checked /></label> + <label><input type="radio" /></label> + </fieldset> + <button-bar> + <button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</button> + <button style="top:0 ; right: 20">Poor CSS</button> + <button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</button> + <button style={{ margin:0, padding:'10px', overflow:'visible' }}>Object CSS</button> + </button-bar> + </form> + </main> + </div> + ); + + let root; + benchmark( () => { + root = render(jsx, scratch, root); + }, ({ ticks, message }) => { + console.log(`PERF: empty diff: ${message}`); + expect(ticks).to.be.below(350 * MULTIPLIER); + done(); + }); + }); + + it('should rerender repeated trees fast', done => { + class Header extends Component { + render() { + return ( + <header> + <h1 class="asdf">a {'b'} c {0} d</h1> + <nav> + <a href="/foo">Foo</a> + <a href="/bar">Bar</a> + </nav> + </header> + ); + } + } + class Form extends Component { + render() { + return ( + <form onSubmit={()=>{}}> + <input type="checkbox" checked={true} /> + <input type="checkbox" checked={false} /> + <fieldset> + <label><input type="radio" checked /></label> + <label><input type="radio" /></label> + </fieldset> + <ButtonBar /> + </form> + ); + } + } + class ButtonBar extends Component { + render() { + return ( + <button-bar> + <Button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</Button> + <Button style="top:0 ; right: 20">Poor CSS</Button> + <Button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</Button> + <Button style={{ margin:0, padding:'10px', overflow:'visible' }}>Object CSS</Button> + </button-bar> + ); + } + } + class Button extends Component { + render(props) { + return <button {...props} />; + } + } + class Main extends Component { + render() { + return <Form />; + } + } + class Root extends Component { + render() { + return ( + <div class="foo bar" data-foo="bar" p={2}> + <Header /> + <Main /> + </div> + ); + } + } + class Empty extends Component { + render() { + return <div />; + } + } + class Parent extends Component { + render({ child:C }) { + return <C />; + } + } + + let root; + benchmark( () => { + root = render(<Parent child={Root} />, scratch, root); + root = render(<Parent child={Empty} />, scratch, root); + }, ({ ticks, message }) => { + console.log(`PERF: repeat diff: ${message}`); + expect(ticks).to.be.below(2000 * MULTIPLIER); + done(); + }); + }); + + it('should construct large VDOM trees fast', done => { + const FIELDS = []; + for (let i=100; i--; ) FIELDS.push((i*999).toString(36)); + + let out = []; + function digest(vnode) { + out.push(vnode); + out.length = 0; + } + benchmark( () => { + digest( + <div class="foo bar" data-foo="bar" p={2}> + <header> + <h1 class="asdf">a {'b'} c {0} d</h1> + <nav> + <a href="/foo">Foo</a> + <a href="/bar">Bar</a> + </nav> + </header> + <main> + <form onSubmit={()=>{}}> + <input type="checkbox" checked /> + <input type="checkbox" /> + <fieldset> + { FIELDS.map( field => ( + <label> + {field}: + <input placeholder={field} /> + </label> + )) } + </fieldset> + <button-bar> + <button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</button> + <button style="top:0 ; right: 20">Poor CSS</button> + <button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</button> + <button style={{ margin:0, padding:'10px', overflow:'visible' }}>Object CSS</button> + </button-bar> + </form> + </main> + </div> + ); + }, ({ ticks, message }) => { + console.log(`PERF: large VTree: ${message}`); + expect(ticks).to.be.below(2000 * MULTIPLIER); + done(); + }); + }); +}); |