mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-12 20:18:41 -09:00
Add perf optimizations (#1541)
* pass `uid` to term * term: keep track of term instance references * sessions: remvoe `write` object overhead * hterm: cache measurement of codepoints for single char strings * sessions: merge less eagerly when we receive a PTY_DATA action * store: handle the side effect of writing to the terminal from a middleware * terms: add terms instance cache * lint
This commit is contained in:
parent
1cd2620da0
commit
dc3b90028b
9 changed files with 54 additions and 26 deletions
|
|
@ -76,7 +76,8 @@ class TermGroup_ extends Component {
|
|||
onData: this.bind(this.props.onData, null, uid),
|
||||
onURLAbort: this.bind(this.props.onURLAbort, null, uid),
|
||||
borderColor: this.props.borderColor,
|
||||
quickEdit: this.props.quickEdit
|
||||
quickEdit: this.props.quickEdit,
|
||||
uid
|
||||
});
|
||||
|
||||
// This will create a new ref_ function for every render,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import uuid from 'uuid';
|
|||
import hterm from '../hterm';
|
||||
import Component from '../component';
|
||||
import getColorList from '../utils/colors';
|
||||
import terms from '../terms';
|
||||
import notify from '../utils/notify';
|
||||
|
||||
export default class Term extends Component {
|
||||
|
|
@ -97,6 +98,7 @@ export default class Term extends Component {
|
|||
|
||||
this.getScreenNode().addEventListener('mouseup', this.handleMouseUp);
|
||||
this.getScreenNode().addEventListener('mousedown', this.handleMouseDown);
|
||||
terms[this.props.uid] = this;
|
||||
}
|
||||
|
||||
handleWheel(e) {
|
||||
|
|
@ -364,6 +366,7 @@ export default class Term extends Component {
|
|||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
terms[this.props.uid] = this;
|
||||
// turn blinking off to prevent leaking a timeout when disposing terminal
|
||||
const prefs = this.term.getPrefs();
|
||||
prefs.set('cursor-blink', false);
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ export default class Terms extends Component {
|
|||
props.ref_(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(next) {
|
||||
const {write} = next;
|
||||
if (write && this.props.write !== write) {
|
||||
this.getTermByUid(write.uid).write(write.data);
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
for (const i in nextProps) {
|
||||
if (i === 'write') {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,12 @@ hterm.TextAttributes.splitWidecharString = function (str) {
|
|||
};
|
||||
|
||||
// hterm Unicode patch
|
||||
const cache = [];
|
||||
lib.wc.strWidth = function (str) {
|
||||
const shouldCache = str.length === 1;
|
||||
if (shouldCache && cache[str] !== undefined) {
|
||||
return cache[str];
|
||||
}
|
||||
const chars = runes(str);
|
||||
let width = 0;
|
||||
let rv = 0;
|
||||
|
|
@ -70,6 +75,9 @@ lib.wc.strWidth = function (str) {
|
|||
}
|
||||
rv += width * ((codePoint <= 0xffff) ? 1 : 2);
|
||||
}
|
||||
if (shouldCache) {
|
||||
cache[str] = rv;
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import {
|
|||
|
||||
const initialState = Immutable({
|
||||
sessions: {},
|
||||
write: null,
|
||||
activeUid: null
|
||||
});
|
||||
|
||||
|
|
@ -26,7 +25,6 @@ function Session(obj) {
|
|||
title: '',
|
||||
cols: null,
|
||||
rows: null,
|
||||
write: null,
|
||||
url: null,
|
||||
cleared: false,
|
||||
shell: '',
|
||||
|
|
@ -34,13 +32,6 @@ function Session(obj) {
|
|||
}).merge(obj);
|
||||
}
|
||||
|
||||
function Write(obj) {
|
||||
return Immutable({
|
||||
uid: '',
|
||||
data: ''
|
||||
}).merge(obj);
|
||||
}
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case SESSION_ADD:
|
||||
|
|
@ -73,15 +64,20 @@ const reducer = (state = initialState, action) => {
|
|||
}, {deep: true});
|
||||
|
||||
case SESSION_PTY_DATA:
|
||||
return state
|
||||
.set('write', Write(action))
|
||||
.merge({
|
||||
sessions: {
|
||||
[action.uid]: {
|
||||
cleared: false
|
||||
// we avoid a direct merge for perf reasons
|
||||
// as this is the most common action
|
||||
if (state.sessions[action.uid] &&
|
||||
state.sessions[action.uid].cleared) {
|
||||
return state
|
||||
.merge({
|
||||
sessions: {
|
||||
[action.uid]: {
|
||||
cleared: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {deep: true});
|
||||
}, {deep: true});
|
||||
}
|
||||
return state;
|
||||
|
||||
case SESSION_PTY_EXIT:
|
||||
if (state.sessions[action.uid]) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import createLogger from 'redux-logger';
|
|||
import rootReducer from '../reducers/index';
|
||||
import effects from '../utils/effects';
|
||||
import * as plugins from '../utils/plugins';
|
||||
import writeMiddleware from './write-middleware';
|
||||
|
||||
export default () => {
|
||||
const logger = createLogger({
|
||||
|
|
@ -17,6 +18,7 @@ export default () => {
|
|||
plugins.middleware,
|
||||
thunk,
|
||||
effects,
|
||||
writeMiddleware,
|
||||
logger
|
||||
),
|
||||
window.devToolsExtension()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import thunk from 'redux-thunk';
|
|||
import rootReducer from '../reducers/index';
|
||||
import effects from '../utils/effects';
|
||||
import * as plugins from '../utils/plugins';
|
||||
import writeMiddleware from './write-middleware';
|
||||
|
||||
export default () =>
|
||||
createStore(
|
||||
|
|
@ -11,6 +12,7 @@ export default () =>
|
|||
thunk,
|
||||
plugins.middleware,
|
||||
thunk,
|
||||
effects
|
||||
effects,
|
||||
writeMiddleware
|
||||
)
|
||||
);
|
||||
|
|
|
|||
14
lib/store/write-middleware.js
Normal file
14
lib/store/write-middleware.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import terms from '../terms';
|
||||
|
||||
// the only side effect we perform from middleware
|
||||
// is to write to the react term instance directly
|
||||
// to avoid a performance hit
|
||||
export default () => next => action => {
|
||||
if (action.type === 'SESSION_PTY_DATA') {
|
||||
const term = terms[action.uid];
|
||||
if (term) {
|
||||
term.write(action.data);
|
||||
}
|
||||
}
|
||||
next(action);
|
||||
};
|
||||
9
lib/terms.js
Normal file
9
lib/terms.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// react Term components add themselves
|
||||
// to this object upon mounting / unmounting
|
||||
// this is to allow imperative access to the
|
||||
// term API, which is a performance
|
||||
// optimization for the most common action
|
||||
// within the system
|
||||
|
||||
const terms = {};
|
||||
export default terms;
|
||||
Loading…
Reference in a new issue