From 6ffb8f545b6a8f21883ebaadcb48f81e23e27ad0 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 3 Jan 2017 11:18:38 -0800 Subject: [PATCH 1/3] Rate limit Viewport.refresh This prevents 1000 scroll events from firing when the buffer is not full Fixes #444 --- src/Viewport.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Viewport.ts b/src/Viewport.ts index 3aa1319fb1..b266dd3e78 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -12,6 +12,7 @@ export class Viewport { private currentRowHeight: number; private lastRecordedBufferLength: number; private lastRecordedViewportHeight: number; + private isRefreshQueued: boolean; /** * Creates a new Viewport. @@ -29,12 +30,22 @@ export class Viewport { this.currentRowHeight = 0; this.lastRecordedBufferLength = 0; this.lastRecordedViewportHeight = 0; + this.isRefreshQueued = false; this.terminal.on('scroll', this.syncScrollArea.bind(this)); this.terminal.on('resize', this.syncScrollArea.bind(this)); this.viewportElement.addEventListener('scroll', this.onScroll.bind(this)); this.syncScrollArea(); + this.refreshLoop(); + } + + private refreshLoop(): void { + if (this.isRefreshQueued) { + this.refresh(); + this.isRefreshQueued = false; + } + window.requestAnimationFrame(this.refreshLoop.bind(this)); } /** @@ -68,15 +79,15 @@ export class Viewport { if (this.lastRecordedBufferLength !== this.terminal.lines.length) { // If buffer height changed this.lastRecordedBufferLength = this.terminal.lines.length; - this.refresh(); + this.isRefreshQueued = true; } else if (this.lastRecordedViewportHeight !== this.terminal.rows) { // If viewport height changed - this.refresh(); + this.isRefreshQueued = true; } else { // If size has changed, refresh viewport var size = this.charMeasureElement.getBoundingClientRect(); if (size.height !== this.currentRowHeight) { - this.refresh(size); + this.isRefreshQueued = true; } } From efdf37b887221d2b9a7951cffa59c9e5323b1022 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 3 Jan 2017 11:23:36 -0800 Subject: [PATCH 2/3] jsdoc --- src/Viewport.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Viewport.ts b/src/Viewport.ts index b266dd3e78..32a71dde0b 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -40,6 +40,9 @@ export class Viewport { this.refreshLoop(); } + /** + * Queues a refresh to be done on next animation frame. + */ private refreshLoop(): void { if (this.isRefreshQueued) { this.refresh(); From ff523bfc790d915f23502d97b427497c8b62189d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 4 Jan 2017 10:30:04 -0800 Subject: [PATCH 3/3] Fix tests --- src/Viewport.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Viewport.test.ts b/src/Viewport.test.ts index 5b106b4345..fc2cd1174c 100644 --- a/src/Viewport.test.ts +++ b/src/Viewport.test.ts @@ -1,6 +1,11 @@ import { assert } from 'chai'; import { Viewport } from './Viewport'; +class MockWindow { + // Disable refreshLoop in test + public requestAnimationFrame() { } +} + describe('Viewport', () => { var terminal; var viewportElement; @@ -11,6 +16,7 @@ describe('Viewport', () => { const CHARACTER_HEIGHT = 10; beforeEach(() => { + (global).window = new MockWindow(); terminal = { lines: [], rows: 0, @@ -73,10 +79,14 @@ describe('Viewport', () => { terminal.rows = 1; assert.equal(scrollAreaElement.style.height, 0 * CHARACTER_HEIGHT + 'px'); viewport.syncScrollArea(); + assert.ok(viewport.isRefreshQueued); + viewport.refresh(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); assert.equal(scrollAreaElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); terminal.lines.push(''); viewport.syncScrollArea(); + assert.ok(viewport.isRefreshQueued); + viewport.refresh(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); assert.equal(scrollAreaElement.style.height, 2 * CHARACTER_HEIGHT + 'px'); });