提交 9aebfa2c 编写于 作者: C Christof Marti

Use ES6 promises

上级 be4e8491
......@@ -5,39 +5,13 @@
import * as paths from 'vs/base/common/paths';
import { URI } from 'vs/base/common/uri';
import { TPromise, TValueCallback } from 'vs/base/common/winjs.base';
import { canceled } from 'vs/base/common/errors';
export class DeferredTPromise<T> extends TPromise<T> {
private completeCallback: TValueCallback<T>;
private errorCallback: (err: any) => void;
constructor() {
let captured: any;
super((c, e) => {
captured = { c, e };
});
this.completeCallback = captured.c;
this.errorCallback = captured.e;
}
public complete(value: T) {
this.completeCallback(value);
}
public error(err: any) {
this.errorCallback(err);
}
public cancel() {
this.errorCallback(canceled());
}
}
export type ValueCallback<T = any> = (value: T | Thenable<T>) => void;
export class DeferredPromise<T> {
private completeCallback: TValueCallback<T>;
private completeCallback: ValueCallback<T>;
private errorCallback: (err: any) => void;
public p: Promise<any>;
......@@ -50,14 +24,20 @@ export class DeferredPromise<T> {
}
public complete(value: T) {
return new Promise(resolve => {
process.nextTick(() => {
this.completeCallback(value);
resolve();
});
});
}
public error(err: any) {
return new Promise(resolve => {
process.nextTick(() => {
this.errorCallback(err);
resolve();
});
});
}
......
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { TPromise } from 'vs/base/common/winjs.base';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { URI } from 'vs/base/common/uri';
......@@ -76,7 +75,7 @@ export interface IPickOptions<T extends IQuickPickItem> {
/**
* an optional property for the item to focus initially.
*/
activeItem?: TPromise<T> | T;
activeItem?: Promise<T> | T;
onKeyMods?: (keyMods: IKeyMods) => void;
onDidFocus?: (entry: T) => void;
......@@ -231,14 +230,14 @@ export interface IQuickInputService {
/**
* Opens the quick input box for selecting items and returns a promise with the user selected item(s) if any.
*/
pick<T extends IQuickPickItem>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: true }, token?: CancellationToken): TPromise<T[]>;
pick<T extends IQuickPickItem>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: false }, token?: CancellationToken): TPromise<T>;
pick<T extends IQuickPickItem>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: Omit<IPickOptions<T>, 'canPickMany'>, token?: CancellationToken): TPromise<T>;
pick<T extends IQuickPickItem>(picks: Thenable<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: true }, token?: CancellationToken): Promise<T[]>;
pick<T extends IQuickPickItem>(picks: Thenable<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: false }, token?: CancellationToken): Promise<T>;
pick<T extends IQuickPickItem>(picks: Thenable<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: Omit<IPickOptions<T>, 'canPickMany'>, token?: CancellationToken): Promise<T>;
/**
* Opens the quick input box for text input and returns a promise with the user typed value if any.
*/
input(options?: IInputOptions, token?: CancellationToken): TPromise<string>;
input(options?: IInputOptions, token?: CancellationToken): Promise<string>;
backButton: IQuickInputButton;
......@@ -251,9 +250,9 @@ export interface IQuickInputService {
navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration): void;
accept(): TPromise<void>;
accept(): Promise<void>;
back(): TPromise<void>;
back(): Promise<void>;
cancel(): TPromise<void>;
cancel(): Promise<void>;
}
......@@ -13,7 +13,6 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { SIDE_BAR_BACKGROUND, SIDE_BAR_FOREGROUND } from 'vs/workbench/common/theme';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { TPromise } from 'vs/base/common/winjs.base';
import { CancellationToken } from 'vs/base/common/cancellation';
import { QuickInputList } from './quickInputList';
import { QuickInputBox } from './quickInputBox';
......@@ -1041,8 +1040,8 @@ export class QuickInputService extends Component implements IQuickInputService {
this.updateStyles();
}
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): TPromise<O extends { canPickMany: true } ? T[] : T> {
return new TPromise<O extends { canPickMany: true } ? T[] : T>((doResolve, reject) => {
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): Promise<O extends { canPickMany: true } ? T[] : T> {
return new Promise<O extends { canPickMany: true } ? T[] : T>((doResolve, reject) => {
let resolve = (result: any) => {
resolve = doResolve;
if (options.onKeyMods) {
......@@ -1117,7 +1116,7 @@ export class QuickInputService extends Component implements IQuickInputService {
input.quickNavigate = options.quickNavigate;
input.contextKey = options.contextKey;
input.busy = true;
TPromise.join([picks, options.activeItem])
Promise.all([picks, options.activeItem])
.then(([items, _activeItem]) => {
activeItem = _activeItem;
input.busy = false;
......@@ -1130,29 +1129,29 @@ export class QuickInputService extends Component implements IQuickInputService {
}
});
input.show();
TPromise.wrap(picks).then(null, err => {
Promise.resolve(picks).then(null, err => {
reject(err);
input.hide();
});
});
}
input(options: IInputOptions = {}, token: CancellationToken = CancellationToken.None): TPromise<string> {
return new TPromise<string>((resolve, reject) => {
input(options: IInputOptions = {}, token: CancellationToken = CancellationToken.None): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (token.isCancellationRequested) {
resolve(undefined);
return;
}
const input = this.createInputBox();
const validateInput = options.validateInput || (() => TPromise.as(undefined));
const validateInput = options.validateInput || (() => <Thenable<undefined>>Promise.resolve(undefined));
const onDidValueChange = debounceEvent(input.onDidChangeValue, (last, cur) => cur, 100);
let validationValue = options.value || '';
let validation = TPromise.wrap(validateInput(validationValue));
let validation = Promise.resolve(validateInput(validationValue));
const disposables = [
input,
onDidValueChange(value => {
if (value !== validationValue) {
validation = TPromise.wrap(validateInput(value));
validation = Promise.resolve(validateInput(value));
validationValue = value;
}
validation.then(result => {
......@@ -1164,7 +1163,7 @@ export class QuickInputService extends Component implements IQuickInputService {
input.onDidAccept(() => {
const value = input.value;
if (value !== validationValue) {
validation = TPromise.wrap(validateInput(value));
validation = Promise.resolve(validateInput(value));
validationValue = value;
}
validation.then(result => {
......@@ -1335,17 +1334,17 @@ export class QuickInputService extends Component implements IQuickInputService {
accept() {
this.onDidAcceptEmitter.fire();
return TPromise.as(undefined);
return Promise.resolve(undefined);
}
back() {
this.onDidTriggerButtonEmitter.fire(this.backButton);
return TPromise.as(undefined);
return Promise.resolve(undefined);
}
cancel() {
this.hide();
return TPromise.as(undefined);
return Promise.resolve(undefined);
}
layout(dimension: dom.Dimension): void {
......@@ -1411,8 +1410,8 @@ export class BackAction extends Action {
super(id, label);
}
public run(): TPromise<any> {
public run(): Promise<any> {
this.quickInputService.back();
return TPromise.as(null);
return Promise.resolve(null);
}
}
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/quickopen';
import { TPromise, ValueCallback } from 'vs/base/common/winjs.base';
import * as nls from 'vs/nls';
import * as browser from 'vs/base/browser/browser';
import * as strings from 'vs/base/common/strings';
......@@ -54,6 +53,8 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
const HELP_PREFIX = '?';
type ValueCallback<T = any> = (value: T | Thenable<T>) => void;
export class QuickOpenController extends Component implements IQuickOpenService {
private static readonly MAX_SHORT_RESPONSE_TIME = 500;
......@@ -73,7 +74,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
private lastSubmittedInputValue: string;
private quickOpenWidget: QuickOpenWidget;
private dimension: Dimension;
private mapResolvedHandlersToPrefix: { [prefix: string]: TPromise<QuickOpenHandler>; } = Object.create(null);
private mapResolvedHandlersToPrefix: { [prefix: string]: Promise<QuickOpenHandler>; } = Object.create(null);
private mapContextKeyToContext: { [id: string]: IContextKey<boolean>; } = Object.create(null);
private handlerOnOpenCalled: { [prefix: string]: boolean; } = Object.create(null);
private promisesToCompleteOnHide: ValueCallback[] = [];
......@@ -153,12 +154,12 @@ export class QuickOpenController extends Component implements IQuickOpenService
}
}
show(prefix?: string, options?: IShowOptions): TPromise<void> {
show(prefix?: string, options?: IShowOptions): Promise<void> {
let quickNavigateConfiguration = options ? options.quickNavigateConfiguration : void 0;
let inputSelection = options ? options.inputSelection : void 0;
let autoFocus = options ? options.autoFocus : void 0;
const promiseCompletedOnHide = new TPromise<void>(c => {
const promiseCompletedOnHide = new Promise<void>(c => {
this.promisesToCompleteOnHide.push(c);
});
......@@ -381,7 +382,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
return;
}
let resultPromise: TPromise<void>;
let resultPromise: Promise<void>;
let resultPromiseDone = false;
if (handlerDescriptor) {
......@@ -426,7 +427,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
});
}
private handleDefaultHandler(handler: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): TPromise<void> {
private handleDefaultHandler(handler: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise<void> {
// Fill in history results if matching and we are configured to search in history
let matchingHistoryEntries: QuickOpenEntry[];
......@@ -514,7 +515,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
}
}
private handleSpecificHandler(handlerDescriptor: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): TPromise<void> {
private handleSpecificHandler(handlerDescriptor: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise<void> {
return this.resolveHandler(handlerDescriptor).then((resolvedHandler: QuickOpenHandler) => {
// Remove handler prefix from search value
......@@ -585,7 +586,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
return mapEntryToPath;
}
private resolveHandler(handler: QuickOpenHandlerDescriptor): TPromise<QuickOpenHandler> {
private resolveHandler(handler: QuickOpenHandlerDescriptor): Promise<QuickOpenHandler> {
let result = this._resolveHandler(handler);
const id = handler.getId();
......@@ -603,11 +604,11 @@ export class QuickOpenController extends Component implements IQuickOpenService
return result.then<QuickOpenHandler>(null, (error) => {
delete this.mapResolvedHandlersToPrefix[id];
return TPromise.wrapError(new Error(`Unable to instantiate quick open handler ${handler.getId()}: ${JSON.stringify(error)}`));
return Promise.reject(new Error(`Unable to instantiate quick open handler ${handler.getId()}: ${JSON.stringify(error)}`));
});
}
private _resolveHandler(handler: QuickOpenHandlerDescriptor): TPromise<QuickOpenHandler> {
private _resolveHandler(handler: QuickOpenHandlerDescriptor): Promise<QuickOpenHandler> {
const id = handler.getId();
// Return Cached
......@@ -835,7 +836,7 @@ export class RemoveFromEditorHistoryAction extends Action {
super(id, label);
}
run(): TPromise<any> {
run(): Thenable<any> {
interface IHistoryPickEntry extends IQuickPickItem {
input: IEditorInput | IResourceInput;
}
......
......@@ -6,14 +6,13 @@
import * as assert from 'assert';
import * as errors from 'vs/base/common/errors';
import * as objects from 'vs/base/common/objects';
import { TPromise } from 'vs/base/common/winjs.base';
import { CacheState } from 'vs/workbench/parts/search/browser/openFileHandler';
import { DeferredTPromise } from 'vs/base/test/common/utils';
import { DeferredPromise } from 'vs/base/test/common/utils';
import { QueryType, IFileQuery } from 'vs/platform/search/common/search';
suite('CacheState', () => {
test('reuse old cacheKey until new cache is loaded', function () {
test('reuse old cacheKey until new cache is loaded', async function () {
const cache = new MockCache();
......@@ -26,7 +25,7 @@ suite('CacheState', () => {
assert.strictEqual(first.isLoaded, false);
assert.strictEqual(first.isUpdating, true);
cache.loading[firstKey].complete(null);
await cache.loading[firstKey].complete(null);
assert.strictEqual(first.isLoaded, true);
assert.strictEqual(first.isUpdating, false);
......@@ -34,18 +33,18 @@ suite('CacheState', () => {
second.load();
assert.strictEqual(second.isLoaded, true);
assert.strictEqual(second.isUpdating, true);
assert.strictEqual(Object.keys(cache.disposing).length, 0);
await cache.awaitDisposal(0);
assert.strictEqual(second.cacheKey, firstKey); // still using old cacheKey
const secondKey = cache.cacheKeys[1];
cache.loading[secondKey].complete(null);
await cache.loading[secondKey].complete(null);
assert.strictEqual(second.isLoaded, true);
assert.strictEqual(second.isUpdating, false);
assert.strictEqual(Object.keys(cache.disposing).length, 1);
await cache.awaitDisposal(1);
assert.strictEqual(second.cacheKey, secondKey);
});
test('do not spawn additional load if previous is still loading', function () {
test('do not spawn additional load if previous is still loading', async function () {
const cache = new MockCache();
......@@ -64,29 +63,29 @@ suite('CacheState', () => {
assert.strictEqual(Object.keys(cache.loading).length, 1); // still only one loading
assert.strictEqual(second.cacheKey, firstKey);
cache.loading[firstKey].complete(null);
await cache.loading[firstKey].complete(null);
assert.strictEqual(second.isLoaded, true);
assert.strictEqual(second.isUpdating, false);
assert.strictEqual(Object.keys(cache.disposing).length, 0);
await cache.awaitDisposal(0);
});
test('do not use previous cacheKey if query changed', function () {
test('do not use previous cacheKey if query changed', async function () {
const cache = new MockCache();
const first = createCacheState(cache);
const firstKey = first.cacheKey;
first.load();
cache.loading[firstKey].complete(null);
await cache.loading[firstKey].complete(null);
assert.strictEqual(first.isLoaded, true);
assert.strictEqual(first.isUpdating, false);
assert.strictEqual(Object.keys(cache.disposing).length, 0);
await cache.awaitDisposal(0);
cache.baseQuery.excludePattern = { '**/node_modules': true };
const second = createCacheState(cache, first);
assert.strictEqual(second.isLoaded, false);
assert.strictEqual(second.isUpdating, false);
assert.strictEqual(Object.keys(cache.disposing).length, 1);
await cache.awaitDisposal(1);
second.load();
assert.strictEqual(second.isLoaded, false);
......@@ -95,40 +94,40 @@ suite('CacheState', () => {
const secondKey = cache.cacheKeys[1];
assert.strictEqual(second.cacheKey, secondKey);
cache.loading[secondKey].complete(null);
await cache.loading[secondKey].complete(null);
assert.strictEqual(second.isLoaded, true);
assert.strictEqual(second.isUpdating, false);
assert.strictEqual(Object.keys(cache.disposing).length, 1);
await cache.awaitDisposal(1);
});
test('dispose propagates', function () {
test('dispose propagates', async function () {
const cache = new MockCache();
const first = createCacheState(cache);
const firstKey = first.cacheKey;
first.load();
cache.loading[firstKey].complete(null);
await cache.loading[firstKey].complete(null);
const second = createCacheState(cache, first);
assert.strictEqual(second.isLoaded, true);
assert.strictEqual(second.isUpdating, false);
assert.strictEqual(Object.keys(cache.disposing).length, 0);
await cache.awaitDisposal(0);
second.dispose();
assert.strictEqual(second.isLoaded, false);
assert.strictEqual(second.isUpdating, false);
assert.strictEqual(Object.keys(cache.disposing).length, 1);
await cache.awaitDisposal(1);
assert.ok(cache.disposing[firstKey]);
});
test('keep using old cacheKey when loading fails', function () {
test('keep using old cacheKey when loading fails', async function () {
const cache = new MockCache();
const first = createCacheState(cache);
const firstKey = first.cacheKey;
first.load();
cache.loading[firstKey].complete(null);
await cache.loading[firstKey].complete(null);
const second = createCacheState(cache, first);
second.load();
......@@ -136,14 +135,14 @@ suite('CacheState', () => {
const origErrorHandler = errors.errorHandler.getUnexpectedErrorHandler();
try {
errors.setUnexpectedErrorHandler(() => null);
cache.loading[secondKey].error('loading failed');
await cache.loading[secondKey].error('loading failed');
} finally {
errors.setUnexpectedErrorHandler(origErrorHandler);
}
assert.strictEqual(second.isLoaded, true);
assert.strictEqual(second.isUpdating, false);
assert.strictEqual(Object.keys(cache.loading).length, 2);
assert.strictEqual(Object.keys(cache.disposing).length, 0);
await cache.awaitDisposal(0);
assert.strictEqual(second.cacheKey, firstKey); // keep using old cacheKey
const third = createCacheState(cache, second);
......@@ -151,15 +150,15 @@ suite('CacheState', () => {
assert.strictEqual(third.isLoaded, true);
assert.strictEqual(third.isUpdating, true);
assert.strictEqual(Object.keys(cache.loading).length, 3);
assert.strictEqual(Object.keys(cache.disposing).length, 0);
await cache.awaitDisposal(0);
assert.strictEqual(third.cacheKey, firstKey);
const thirdKey = cache.cacheKeys[2];
cache.loading[thirdKey].complete(null);
await cache.loading[thirdKey].complete(null);
assert.strictEqual(third.isLoaded, true);
assert.strictEqual(third.isUpdating, false);
assert.strictEqual(Object.keys(cache.loading).length, 3);
assert.strictEqual(Object.keys(cache.disposing).length, 2);
await cache.awaitDisposal(2);
assert.strictEqual(third.cacheKey, thirdKey); // recover with next successful load
});
......@@ -175,8 +174,10 @@ suite('CacheState', () => {
class MockCache {
public cacheKeys: string[] = [];
public loading: { [cacheKey: string]: DeferredTPromise<any> } = {};
public disposing: { [cacheKey: string]: DeferredTPromise<void> } = {};
public loading: { [cacheKey: string]: DeferredPromise<any> } = {};
public disposing: { [cacheKey: string]: DeferredPromise<void> } = {};
private _awaitDisposal: (() => void)[][] = [];
public baseQuery: IFileQuery = {
type: QueryType.File
......@@ -187,16 +188,31 @@ suite('CacheState', () => {
return objects.assign({ cacheKey: cacheKey }, this.baseQuery);
}
public load(query: IFileQuery): TPromise<any> {
const promise = new DeferredTPromise<any>();
public load(query: IFileQuery): Promise<any> {
const promise = new DeferredPromise<any>();
this.loading[query.cacheKey] = promise;
return promise;
return promise.p;
}
public dispose(cacheKey: string): TPromise<void> {
const promise = new DeferredTPromise<void>();
public dispose(cacheKey: string): Promise<void> {
const promise = new DeferredPromise<void>();
this.disposing[cacheKey] = promise;
return promise;
const n = Object.keys(this.disposing).length;
for (const done of this._awaitDisposal[n] || []) {
done();
}
delete this._awaitDisposal[n];
return promise.p;
}
public awaitDisposal(n: number) {
return new Promise(resolve => {
if (n === Object.keys(this.disposing).length) {
resolve();
} else {
(this._awaitDisposal[n] || (this._awaitDisposal[n] = [])).push(resolve);
}
});
}
}
});
......@@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TPromise } from 'vs/base/common/winjs.base';
import { URI } from 'vs/base/common/uri';
import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
import { IModelService } from 'vs/editor/common/services/modelService';
......@@ -26,9 +25,9 @@ export class WalkThroughContentProvider implements ITextModelContentProvider, IW
this.textModelResolverService.registerTextModelContentProvider(Schemas.walkThrough, this);
}
public provideTextContent(resource: URI): TPromise<ITextModel> {
public provideTextContent(resource: URI): Thenable<ITextModel> {
const query = resource.query ? JSON.parse(resource.query) : {};
const content: TPromise<string | ITextBufferFactory> = (query.moduleId ? new TPromise<string>((resolve, reject) => {
const content: Thenable<string | ITextBufferFactory> = (query.moduleId ? new Promise<string>((resolve, reject) => {
require([query.moduleId], content => {
try {
resolve(content.default());
......@@ -61,7 +60,7 @@ export class WalkThroughSnippetContentProvider implements ITextModelContentProvi
this.textModelResolverService.registerTextModelContentProvider(Schemas.walkThroughSnippet, this);
}
public provideTextContent(resource: URI): TPromise<ITextModel> {
public provideTextContent(resource: URI): Thenable<ITextModel> {
return this.textFileService.resolveTextContent(URI.file(resource.fsPath)).then(content => {
let codeEditorModel = this.modelService.getModel(resource);
if (!codeEditorModel) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册