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

list: improve row cache

上级 0ad0cf0c
......@@ -12,17 +12,19 @@ import { IScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEleme
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/impl/scrollableElement';
import { RangeMap } from './rangeMap';
import { IScrollEvent, IDelegate, IRendererMap } from './list';
import { RowCache } from './rowCache';
import { RowCache, IRow } from './rowCache';
interface IItem {
domNode: HTMLElement;
height: number;
templateId: string;
row: IRow;
}
export class List<T> implements IScrollable {
private items: IItem[];
private rangeMap: RangeMap;
private rowCache: RowCache<T>;
private cache: RowCache<T>;
private _scrollTop: number;
private _viewHeight: number;
......@@ -41,7 +43,7 @@ export class List<T> implements IScrollable {
constructor(container: HTMLElement, delegate: IDelegate<T>, renderers: IRendererMap<T>) {
this.items = [];
this.rangeMap = new RangeMap();
this.rowCache = new RowCache(renderers);
this.cache = new RowCache(renderers);
this.domNode = document.createElement('div');
this.domNode.className = 'monaco-list';
......@@ -176,32 +178,38 @@ export class List<T> implements IScrollable {
private insertItemInDOM(index: number): void {
const item = this.items[index];
if (!item.domNode) {
// item.domNode = this.cache.alloc(this.templateId);
item.domNode = document.createElement('div');
if (!item.row) {
item.row = this.cache.alloc(item.templateId);
// used in reverse lookup from HTMLElement to Item
// (<any> this.element)[TreeView.BINDING] = this;
}
if (item.domNode.parentElement) {
if (item.row.domNode.parentElement) {
return;
}
const nextItem = this.items[index + 1];
if (nextItem && nextItem.domNode) {
this.rowsContainer.insertBefore(item.domNode, nextItem.domNode);
if (nextItem && nextItem.row) {
this.rowsContainer.insertBefore(item.row.domNode, nextItem.row.domNode);
} else {
this.rowsContainer.appendChild(item.domNode);
this.rowsContainer.appendChild(item.row.domNode);
}
this.renderItem(index);
}
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 {
......
......@@ -5,10 +5,10 @@
import { IRendererMap } from './list';
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 {
element: HTMLElement;
domNode: HTMLElement;
templateId: string;
templateData: any;
}
......@@ -32,72 +32,74 @@ export class RowCache<T> implements IDisposable {
private scrollingRow: IRow;
constructor(private renderers: IRendererMap<T>) {
this.cache = { '': [] };
this.cache = Object.create(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();
if (!result) {
const content = document.createElement('div');
content.className = 'content';
const row = document.createElement('div');
row.appendChild(content);
const domNode = $('div');
const content = append(domNode, $('.content'));
const renderer = this.renderers[templateId];
result = {
element: row,
templateId: templateId,
templateData: renderer.renderTemplate(content)
};
const templateData = renderer.renderTemplate(content);
result = { domNode, templateId, templateData };
}
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) {
removeFromParent(row.element);
this.getTemplateCache(templateId).push(row);
removeFromParent(row.domNode);
this.getTemplateCache(row.templateId).push(row);
return;
}
if (this.scrollingRow) {
var lastKnownScrollTime = getLastScrollTime(this.scrollingRow.element);
var lastKnownScrollTime = getLastScrollTime(this.scrollingRow.domNode);
if (lastKnownScrollTime > lastScrollTime) {
removeFromParent(row.element);
this.getTemplateCache(templateId).push(row);
removeFromParent(row.domNode);
this.getTemplateCache(row.templateId).push(row);
return;
}
if (this.scrollingRow.element.parentElement) {
removeFromParent(this.scrollingRow.element);
DOM.removeClass(this.scrollingRow.element, 'scrolling');
if (this.scrollingRow.domNode.parentElement) {
removeFromParent(this.scrollingRow.domNode);
removeClass(this.scrollingRow.domNode, 'scrolling');
this.getTemplateCache(this.scrollingRow.templateId).push(this.scrollingRow);
}
}
this.scrollingRow = row;
DOM.addClass(this.scrollingRow.element, 'scrolling');
addClass(this.scrollingRow.domNode, 'scrolling');
}
private getTemplateCache(templateId: string): IRow[] {
return this.cache[templateId] || (this.cache[templateId] = []);
}
public garbageCollect(): void {
garbageCollect(): void {
if (this.cache) {
Object.keys(this.cache).forEach(templateId => {
this.cache[templateId].forEach(cachedRow => {
const renderer = this.renderers[templateId];
renderer.disposeTemplate(cachedRow.templateData);
cachedRow.element = null;
cachedRow.domNode = null;
cachedRow.templateData = null;
});
......@@ -112,7 +114,7 @@ export class RowCache<T> implements IDisposable {
}
}
public dispose(): void {
dispose(): void {
this.garbageCollect();
this.cache = null;
this.renderers = null;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册