From 14b0ce99d81309edcabf92cec44bb431d5be7975 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 4 Jul 2018 09:14:21 +0200 Subject: [PATCH] debt - async winjs.promise, add cancelation token --- .../electron-browser/mainThreadDecorations.ts | 16 +++++----- .../decorations/browser/decorations.ts | 4 +-- .../decorations/browser/decorationsService.ts | 30 ++++++++++++------- .../test/browser/decorationsService.test.ts | 16 +++++++--- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts index 1f8d8af2c36..4cef3fd8b1b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts @@ -10,14 +10,14 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape, DecorationData, DecorationRequest } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; -import { TPromise } from 'vs/base/common/winjs.base'; import { values } from 'vs/base/common/collections'; +import { CancellationToken } from 'vs/base/common/cancellation'; class DecorationRequestsQueue { private _idPool = 0; private _requests: { [id: number]: DecorationRequest } = Object.create(null); - private _resolver: { [id: number]: Function } = Object.create(null); + private _resolver: { [id: number]: (data: DecorationData) => any } = Object.create(null); private _timer: number; @@ -27,16 +27,18 @@ class DecorationRequestsQueue { // } - enqueue(handle: number, uri: URI): TPromise { + enqueue(handle: number, uri: URI, token: CancellationToken): Promise { const id = ++this._idPool; - return new TPromise((resolve, reject) => { + const result = new Promise(resolve => { this._requests[id] = { id, handle, uri }; this._resolver[id] = resolve; this._processQueue(); - }, () => { + }); + token.onCancellationRequested(() => { delete this._requests[id]; delete this._resolver[id]; }); + return result; } private _processQueue(): void { @@ -87,8 +89,8 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { const registration = this._decorationsService.registerDecorationsProvider({ label, onDidChange: emitter.event, - provideDecorations: (uri) => { - return this._requestQueue.enqueue(handle, uri).then(data => { + provideDecorations: (uri, token) => { + return this._requestQueue.enqueue(handle, uri, token).then(data => { if (!data) { return undefined; } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index e777db83119..6d1e6607375 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -9,7 +9,7 @@ import URI from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { TPromise } from 'vs/base/common/winjs.base'; +import { CancellationToken } from 'vs/base/common/cancellation'; export const IDecorationsService = createDecorator('IFileDecorationsService'); @@ -32,7 +32,7 @@ export interface IDecoration { export interface IDecorationsProvider { readonly label: string; readonly onDidChange: Event; - provideDecorations(uri: URI): IDecorationData | TPromise; + provideDecorations(uri: URI, token: CancellationToken): IDecorationData | Thenable; } export interface IResourceDecorationChangeEvent { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 513955a5b04..146bafc26a3 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -17,8 +17,8 @@ import { IdGenerator } from 'vs/base/common/idGenerator'; import { IIterator } from 'vs/base/common/iterator'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { localize } from 'vs/nls'; -import { TPromise } from 'vs/base/common/winjs.base'; import { isPromiseCanceledError } from 'vs/base/common/errors'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; class DecorationRule { @@ -180,7 +180,7 @@ class DecorationStyles { let usedDecorations = new Set(); for (let e = iter.next(); !e.done; e = iter.next()) { e.value.data.forEach((value, key) => { - if (!isThenable(value) && value) { + if (value && !(value instanceof DecorationDataRequest)) { usedDecorations.add(DecorationRule.keyOf(value)); } }); @@ -229,9 +229,16 @@ class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { } } +class DecorationDataRequest { + constructor( + readonly source: CancellationTokenSource, + readonly thenable: Thenable, + ) { } +} + class DecorationProviderWrapper { - readonly data = TernarySearchTree.forPaths | IDecorationData>(); + readonly data = TernarySearchTree.forPaths(); private readonly _dispoable: IDisposable; constructor( @@ -275,7 +282,7 @@ class DecorationProviderWrapper { item = this._fetchData(uri); } - if (item && !isThenable(item)) { + if (item && !(item instanceof DecorationDataRequest)) { // found something (which isn't pending anymore) callback(item, false); } @@ -285,7 +292,7 @@ class DecorationProviderWrapper { const iter = this.data.findSuperstr(key); if (iter) { for (let item = iter.next(); !item.done; item = iter.next()) { - if (item.value && !isThenable(item.value)) { + if (item.value && !(item.value instanceof DecorationDataRequest)) { callback(item.value, true); } } @@ -297,27 +304,28 @@ class DecorationProviderWrapper { // check for pending request and cancel it const pendingRequest = this.data.get(uri.toString()); - if (TPromise.is(pendingRequest)) { - pendingRequest.cancel(); + if (pendingRequest instanceof DecorationDataRequest) { + pendingRequest.source.cancel(); this.data.delete(uri.toString()); } - const dataOrThenable = this._provider.provideDecorations(uri); + const source = new CancellationTokenSource(); + const dataOrThenable = this._provider.provideDecorations(uri, source.token); if (!isThenable(dataOrThenable)) { // sync -> we have a result now return this._keepItem(uri, dataOrThenable); } else { // async -> we have a result soon - const request = TPromise.wrap(dataOrThenable).then(data => { + const request = new DecorationDataRequest(source, Promise.resolve(dataOrThenable).then(data => { if (this.data.get(uri.toString()) === request) { this._keepItem(uri, data); } - }, err => { + }).catch(err => { if (!isPromiseCanceledError(err) && this.data.get(uri.toString()) === request) { this.data.delete(uri.toString()); } - }); + })); this.data.set(uri.toString(), request); return undefined; diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index f8469b69e23..c94ec82944a 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -12,6 +12,7 @@ import URI from 'vs/base/common/uri'; import { Event, toPromise, Emitter } from 'vs/base/common/event'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { TPromise } from 'vs/base/common/winjs.base'; +import { CancellationToken } from 'vs/base/common/cancellation'; suite('DecorationsService', function () { @@ -34,7 +35,7 @@ suite('DecorationsService', function () { readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; - return new TPromise(resolve => { + return new Promise(resolve => { setTimeout(() => resolve({ color: 'someBlue', tooltip: 'T' @@ -174,6 +175,7 @@ suite('DecorationsService', function () { test('Decorations not showing up for second root folder #48502', async function () { let cancelCount = 0; + let winjsCancelCount = 0; let callCount = 0; let provider = new class implements IDecorationsProvider { @@ -183,14 +185,19 @@ suite('DecorationsService', function () { label: string = 'foo'; - provideDecorations(uri: URI): TPromise { + provideDecorations(uri: URI, token: CancellationToken): TPromise { + + token.onCancellationRequested(() => { + cancelCount += 1; + }); + return new TPromise(resolve => { callCount += 1; setTimeout(() => { resolve({ letter: 'foo' }); }, 10); }, () => { - cancelCount += 1; + winjsCancelCount += 1; }); } }; @@ -204,6 +211,7 @@ suite('DecorationsService', function () { service.getDecoration(uri, false); assert.equal(cancelCount, 1); + assert.equal(winjsCancelCount, 0); assert.equal(callCount, 2); reg.dispose(); @@ -219,7 +227,7 @@ suite('DecorationsService', function () { if (uri.path.match(/hello$/)) { return { tooltip: 'FOO', weight: 17, bubble: true }; } else { - return new TPromise(_resolve => resolve = _resolve); + return new Promise(_resolve => resolve = _resolve); } } }); -- GitLab