Files
react/perf/lib/BrowserPerfRunnerContext.react.js
2014-01-06 12:26:40 -05:00

196 lines
5.6 KiB
JavaScript

var BenchmarkQueue = React.createClass({
propTypes: {
debug: React.PropTypes.bool,
onChange: React.PropTypes.func.isRequired,
initialQueue: React.PropTypes.array.isRequired,
maxTime: React.PropTypes.number,
onCompleteEach: React.PropTypes.func,
onError: React.PropTypes.func
},
getDefaultProps: function(){
return {
maxTime: 5
};
},
getInitialState: function(){
return {
queue: this.props.initialQueue.slice()
};
},
setItemState: function(state){
state.test = this.state.queue[0].test;
state.react = this.state.queue[0].react;
this.props.onChange(state);
},
handleContextReady: function(window){
var benchmark = window.Benchmark(window.exports);
benchmark.options.maxTime = this.props.maxTime; //DEBUG
var itemState = {
testRunnerURL: window.location.href,
name: window.exports.name,
platform: window.Benchmark.platform.description,
reactVersion: window.React.version,
isMinified: (function(){
var code = window.React.renderComponent.toString();
return code.indexOf(',') - code.indexOf('(') <= 2;
}())
};
this.setItemState(itemState);
var self = this;
benchmark.on('start error cycle complete', function(){
var stats = JSON.parse(JSON.stringify(benchmark.stats));
itemState.stats = stats;
itemState.isRunning = benchmark.running;
itemState.error = benchmark.error;
self.setItemState(itemState);
});
if (this.props.onError) {
benchmark.on('error', this.props.onError);
}
benchmark.on('complete', function(){
var queue = self.state.queue.slice();
var queueItem = queue.shift();
if (self.props.onCompleteEach) {
self.props.onCompleteEach(queueItem);
}
self.setState({ queue:queue });
});
benchmark.run({async:true});
},
shouldComponentUpdate: function(nextProps, nextState){
return nextState.queue.length < this.state.queue.length;
},
render: function(){
if (!(this.state.queue && this.state.queue.length > 0)){
return React.DOM.div({style:{display:'none'}});
}
return BrowserPerfRunnerContext({
debug: this.props.debug,
test: this.state.queue[0].test,
react: this.state.queue[0].react,
onReady: this.handleContextReady
});
}
});
var BrowserPerfRunnerContext = React.createClass({
propTypes: {
debug: React.PropTypes.bool,
test: function(object, key){
React.PropTypes.string.isRequired(object, key);
if (/\.jsx?$/i.test(object[key])) return;
throw Error('Expected `' + key + '` to be a test file name with extension `.js` or `.jsx`');
},
react: function(object, key){
React.PropTypes.string.isRequired(object, key);
if (/^(?:builds\/.+|edge|previous|(?:\d+\.){2}\d+)$/.test(object[key])) return;
throw Error('Expected `' + key + '` prop to be a valid react version string, build string or "edge" or "previous"');
},
onReady: React.PropTypes.func.isRequired
},
getInitialState: function(){
return {
testRunnerURL:'about:blank'
};
},
// _handleFrameError: function(error){
// console.error('BrowserPerfRunnerContext', error);
// },
//
// _handleFrameLoad: function(event){
// console.log('BrowserPerfRunnerContext', event);
// },
//
_handleMessage: function(event){
if (location.href.indexOf(event.origin) !== 0)
return console.debug('BrowserPerfRunnerContext#_handleMessage ignored message from ' + event.origin);
if (event.source.location.href.indexOf(this.state.testRunnerURL) === -1)
return console.debug('BrowserPerfRunnerContext#_handleMessage ignored message from ' + event.source.location.href);
if (event.data !== 'Ready!')
return console.debug('BrowserPerfRunnerContext#_handleMessage ignored message ' + JSON.stringify(event.data));
this.props.onReady(event.source);
},
_getTestRunnerURL: function(props){
return 'runner.html' +
'?' +
'debug=' + (props.debug ? 1 : 0) +
'&' +
'react=' + encodeURIComponent(props.react) +
'&' +
'test=' + encodeURIComponent(props.test)
},
_renderState: function(props){
return {
testRunnerURL: this._getTestRunnerURL(props)
};
},
componentDidMount: function(){
var node = this.refs.iframe.getDOMNode();
// node.onload = this._handleFrameLoad;
// node.onerror = this._handleFrameError;
if (window.addEventListener) {
window.addEventListener('message', this._handleMessage, false);
} else if (window.attachEvent) {
window.attachEvent('onmessage', this._handleMessage);
} else {
throw Error('cannot attach onmessage listener');
}
this.setState(this._renderState(this.props));
},
componentWillUnmount: function(){
if (window.removeEventListener) {
window.removeEventListener('message', this._handleMessage);
} else if (window.detachEvent) {
window.detachEvent('onmessage', this._handleMessage);
} else {
throw Error('cannot detach onmessage listener');
}
this.refs.iframe.getDOMNode().src = '';
},
componentWillReceiveProps: function(nextProps){
this.setState(this._renderState(nextProps));
},
shouldComponentUpdate: function(nextProps, nextState){
return nextState.testRunnerURL != this.state.testRunnerURL;
},
render: function(){
return (
React.DOM.iframe({
ref: 'iframe',
name: "BrowserPerfRunnerContextFrame",
style: this.style,
src: this.state.testRunnerURL
})
);
},
style: {
position: 'absolute',
right: '100%',
bottom: '100%'
}
});