Skip to content

Commit

Permalink
Use a time-based limit to Terminal._innerWrite
Browse files Browse the repository at this point in the history
The idea is that it should run for a bit and then let the renderer draw
a frame so that the terminal look responsive. The existing approach
limits the work done using a fixed number elements from the write
buffer so the duration of a frame can vary widely.

This approach looks at the clock to determine when to stop, we basically
allocate an amount of time each frame to write, while the rest can be
used for rendering.

From my tests this change makes the terminal feel a lot smoother.
  • Loading branch information
juancampa committed Dec 8, 2018
1 parent b5f1c33 commit fd34cae
Showing 1 changed file with 13 additions and 7 deletions.
20 changes: 13 additions & 7 deletions src/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ const document = (typeof window !== 'undefined') ? window.document : null;
const WRITE_BUFFER_PAUSE_THRESHOLD = 5;

/**
* The number of writes to perform in a single batch before allowing the
* renderer to catch up with a 0ms setTimeout.
* The max number of ms to spend on writes before allowing the renderer to
* catch up with a 0ms setTimeout. A value of < 33 to keep us close to
* 30fps, and a value of < 16 to try to run at 60fps. Of course, the real FPS
* depends on the time it takes for the renderer to draw the frame.
*/
const WRITE_BATCH_SIZE = 300;
const WRITE_TIMEOUT_MS = 12;

/**
* The set of options that only have an effect when set in the Terminal constructor.
Expand Down Expand Up @@ -1358,13 +1360,13 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this.writeBuffer = [];
}

const writeBatch = this.writeBuffer.splice(0, WRITE_BATCH_SIZE);
while (writeBatch.length > 0) {
const data = writeBatch.shift();
const time = Date.now();
while (this.writeBuffer.length > 0) {
const data = this.writeBuffer.shift();

// If XOFF was sent in order to catch up with the pty process, resume it if
// the writeBuffer is empty to allow more data to come in.
if (this._xoffSentToCatchUp && writeBatch.length === 0 && this.writeBuffer.length === 0) {
if (this._xoffSentToCatchUp && this.writeBuffer.length === 0 && this.writeBuffer.length === 0) {
this.handler(C0.DC1);
this._xoffSentToCatchUp = false;
}
Expand All @@ -1382,6 +1384,10 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II

this.updateRange(this.buffer.y);
this.refresh(this._refreshStart, this._refreshEnd);

if (Date.now() - time >= WRITE_TIMEOUT_MS) {
break;
}
}
if (this.writeBuffer.length > 0) {
// Allow renderer to catch up before processing the next batch
Expand Down

0 comments on commit fd34cae

Please sign in to comment.