提交 785b4f37 编写于 作者: J Joao Moreno

list: improve row cache

上级 0ad0cf0c
...@@ -12,17 +12,19 @@ import { IScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEleme ...@@ -12,17 +12,19 @@ import { IScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEleme
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/impl/scrollableElement'; import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/impl/scrollableElement';
import { RangeMap } from './rangeMap'; import { RangeMap } from './rangeMap';
import { IScrollEvent, IDelegate, IRendererMap } from './list'; import { IScrollEvent, IDelegate, IRendererMap } from './list';
import { RowCache } from './rowCache'; import { RowCache, IRow } from './rowCache';
interface IItem { interface IItem {
domNode: HTMLElement; height: number;
templateId: string;
row: IRow;
} }
export class List<T> implements IScrollable { export class List<T> implements IScrollable {
private items: IItem[]; private items: IItem[];
private rangeMap: RangeMap; private rangeMap: RangeMap;
private rowCache: RowCache<T>; private cache: RowCache<T>;
private _scrollTop: number; private _scrollTop: number;
private _viewHeight: number; private _viewHeight: number;
...@@ -41,7 +43,7 @@ export class List<T> implements IScrollable { ...@@ -41,7 +43,7 @@ export class List<T> implements IScrollable {
constructor(container: HTMLElement, delegate: IDelegate<T>, renderers: IRendererMap<T>) { constructor(container: HTMLElement, delegate: IDelegate<T>, renderers: IRendererMap<T>) {
this.items = []; this.items = [];
this.rangeMap = new RangeMap(); this.rangeMap = new RangeMap();
this.rowCache = new RowCache(renderers); this.cache = new RowCache(renderers);
this.domNode = document.createElement('div'); this.domNode = document.createElement('div');
this.domNode.className = 'monaco-list'; this.domNode.className = 'monaco-list';
...@@ -176,32 +178,38 @@ export class List<T> implements IScrollable { ...@@ -176,32 +178,38 @@ export class List<T> implements IScrollable {
private insertItemInDOM(index: number): void { private insertItemInDOM(index: number): void {
const item = this.items[index]; const item = this.items[index];
if (!item.domNode) { if (!item.row) {
// item.domNode = this.cache.alloc(this.templateId); item.row = this.cache.alloc(item.templateId);
item.domNode = document.createElement('div');
// used in reverse lookup from HTMLElement to Item // used in reverse lookup from HTMLElement to Item
// (<any> this.element)[TreeView.BINDING] = this; // (<any> this.element)[TreeView.BINDING] = this;
} }
if (item.domNode.parentElement) { if (item.row.domNode.parentElement) {
return; return;
} }
const nextItem = this.items[index + 1]; const nextItem = this.items[index + 1];
if (nextItem && nextItem.domNode) { if (nextItem && nextItem.row) {
this.rowsContainer.insertBefore(item.domNode, nextItem.domNode); this.rowsContainer.insertBefore(item.row.domNode, nextItem.row.domNode);
} else { } else {
this.rowsContainer.appendChild(item.domNode); this.rowsContainer.appendChild(item.row.domNode);
} }
this.renderItem(index); this.renderItem(index);
} }
private removeItemFromDOM(index: number): void { private removeItemFromDOM(index: number): void {
// TODO const item = this.items[index];
if (!item.row) {
return;
}
// (<any> this.element)[TreeView.BINDING] = null;
this.cache.release(item.row);
item.row = null;
} }
private renderItem(index: number): void { private renderItem(index: number): void {
......
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
import { IRendererMap } from './list'; import { IRendererMap } from './list';
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
import * as DOM from 'vs/base/browser/dom'; import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom';
export interface IRow { export interface IRow {
element: HTMLElement; domNode: HTMLElement;
templateId: string; templateId: string;
templateData: any; templateData: any;
} }
...@@ -32,72 +32,74 @@ export class RowCache<T> implements IDisposable { ...@@ -32,72 +32,74 @@ export class RowCache<T> implements IDisposable {
private scrollingRow: IRow; private scrollingRow: IRow;
constructor(private renderers: IRendererMap<T>) { constructor(private renderers: IRendererMap<T>) {
this.cache = { '': [] }; this.cache = Object.create(null);
this.scrollingRow = null; this.scrollingRow = null;
} }
public alloc(templateId: string): IRow { /**
* Returns a row either by creating a new one or reusing
* a previously released row which shares the same templateId.
*/
alloc(templateId: string): IRow {
let result = this.getTemplateCache(templateId).pop(); let result = this.getTemplateCache(templateId).pop();
if (!result) { if (!result) {
const content = document.createElement('div'); const domNode = $('div');
content.className = 'content'; const content = append(domNode, $('.content'));
const row = document.createElement('div');
row.appendChild(content);
const renderer = this.renderers[templateId]; const renderer = this.renderers[templateId];
const templateData = renderer.renderTemplate(content);
result = { result = { domNode, templateId, templateData };
element: row,
templateId: templateId,
templateData: renderer.renderTemplate(content)
};
} }
return result; return result;
} }
public release(templateId: string, row: IRow): void { /**
var lastScrollTime = getLastScrollTime(row.element); * Releases the row for eventual reuse. The row's domNode
* will eventually be removed from its parent, given that
* it is not the currently scrolling row (for OS X ballistic
* scrolling).
*/
release(row: IRow): void {
var lastScrollTime = getLastScrollTime(row.domNode);
if (!lastScrollTime) { if (!lastScrollTime) {
removeFromParent(row.element); removeFromParent(row.domNode);
this.getTemplateCache(templateId).push(row); this.getTemplateCache(row.templateId).push(row);
return; return;
} }
if (this.scrollingRow) { if (this.scrollingRow) {
var lastKnownScrollTime = getLastScrollTime(this.scrollingRow.element); var lastKnownScrollTime = getLastScrollTime(this.scrollingRow.domNode);
if (lastKnownScrollTime > lastScrollTime) { if (lastKnownScrollTime > lastScrollTime) {
removeFromParent(row.element); removeFromParent(row.domNode);
this.getTemplateCache(templateId).push(row); this.getTemplateCache(row.templateId).push(row);
return; return;
} }
if (this.scrollingRow.element.parentElement) { if (this.scrollingRow.domNode.parentElement) {
removeFromParent(this.scrollingRow.element); removeFromParent(this.scrollingRow.domNode);
DOM.removeClass(this.scrollingRow.element, 'scrolling'); removeClass(this.scrollingRow.domNode, 'scrolling');
this.getTemplateCache(this.scrollingRow.templateId).push(this.scrollingRow); this.getTemplateCache(this.scrollingRow.templateId).push(this.scrollingRow);
} }
} }
this.scrollingRow = row; this.scrollingRow = row;
DOM.addClass(this.scrollingRow.element, 'scrolling'); addClass(this.scrollingRow.domNode, 'scrolling');
} }
private getTemplateCache(templateId: string): IRow[] { private getTemplateCache(templateId: string): IRow[] {
return this.cache[templateId] || (this.cache[templateId] = []); return this.cache[templateId] || (this.cache[templateId] = []);
} }
public garbageCollect(): void { garbageCollect(): void {
if (this.cache) { if (this.cache) {
Object.keys(this.cache).forEach(templateId => { Object.keys(this.cache).forEach(templateId => {
this.cache[templateId].forEach(cachedRow => { this.cache[templateId].forEach(cachedRow => {
const renderer = this.renderers[templateId]; const renderer = this.renderers[templateId];
renderer.disposeTemplate(cachedRow.templateData); renderer.disposeTemplate(cachedRow.templateData);
cachedRow.element = null; cachedRow.domNode = null;
cachedRow.templateData = null; cachedRow.templateData = null;
}); });
...@@ -112,7 +114,7 @@ export class RowCache<T> implements IDisposable { ...@@ -112,7 +114,7 @@ export class RowCache<T> implements IDisposable {
} }
} }
public dispose(): void { dispose(): void {
this.garbageCollect(); this.garbageCollect();
this.cache = null; this.cache = null;
this.renderers = null; this.renderers = null;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册