From 3fc493a0e49e21058115044b30db77ecab056601 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 8 May 2018 14:28:08 -0700 Subject: [PATCH] Make geterr async --- .../src/features/bufferSyncSupport.ts | 2 +- .../src/typescriptService.ts | 3 +- .../src/typescriptServiceClient.ts | 43 ++++++++++++++----- .../src/utils/tracer.ts | 7 +++ 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index fe73d418cc03f..519c3a66491c9 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -310,7 +310,7 @@ export default class BufferSyncSupport { const token = new CancellationTokenSource(); const getErr = this.pendingGetErr = { - request: this.client.execute('geterr', args, token.token) + request: this.client.executeAsync('geterr', args, token.token) .then(undefined, () => { }) .then(() => { if (this.pendingGetErr === getErr) { diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index cc8b449105064..d5c882111f424 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -30,7 +30,6 @@ export interface ITypeScriptServiceClient { execute(command: 'open', args: Proto.OpenRequestArgs, expectedResult: boolean, token?: CancellationToken): Promise; execute(command: 'close', args: Proto.FileRequestArgs, expectedResult: boolean, token?: CancellationToken): Promise; execute(command: 'change', args: Proto.ChangeRequestArgs, expectedResult: boolean, token?: CancellationToken): Promise; - execute(command: 'geterr', args: Proto.GeterrRequestArgs, expectedResult: boolean, token?: CancellationToken): Promise; execute(command: 'quickinfo', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise; execute(command: 'completions', args: Proto.CompletionsRequestArgs, token?: CancellationToken): Promise; execute(command: 'completionEntryDetails', args: Proto.CompletionDetailsRequestArgs, token?: CancellationToken): Promise; @@ -60,4 +59,6 @@ export interface ITypeScriptServiceClient { execute(command: 'organizeImports', args: Proto.OrganizeImportsRequestArgs, token?: CancellationToken): Promise; execute(command: 'getOutliningSpans', args: Proto.FileRequestArgs, token: CancellationToken): Promise; execute(command: string, args: any, expectedResult: boolean | CancellationToken, token?: CancellationToken): Promise; + + executeAsync(command: 'geterr', args: Proto.GeterrRequestArgs, token: CancellationToken): Promise; } \ No newline at end of file diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index f16d2f035ce26..315f4ddd93b77 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -42,23 +42,31 @@ interface CallbackItem { class CallbackMap { private readonly callbacks: Map = new Map(); + private readonly asyncCallbacks: Map = new Map(); public pendingResponses: number = 0; public destroy(e: any): void { for (const callback of this.callbacks.values()) { callback.e(e); } + for (const callback of this.asyncCallbacks.values()) { + callback.e(e); + } this.callbacks.clear(); this.pendingResponses = 0; } - public add(seq: number, callback: CallbackItem) { - this.callbacks.set(seq, callback); - ++this.pendingResponses; + public add(seq: number, callback: CallbackItem, isAsync: boolean) { + if (isAsync) { + this.asyncCallbacks.set(seq, callback); + } else { + this.callbacks.set(seq, callback); + ++this.pendingResponses; + } } public fetch(seq: number): CallbackItem | undefined { - const callback = this.callbacks.get(seq); + const callback = this.callbacks.get(seq) || this.asyncCallbacks.get(seq); this.delete(seq); return callback; } @@ -66,13 +74,16 @@ class CallbackMap { private delete(seq: number) { if (this.callbacks.delete(seq)) { --this.pendingResponses; + } else { + this.asyncCallbacks.delete(seq); } } } interface RequestItem { - request: Proto.Request; + readonly request: Proto.Request; callbacks: CallbackItem | null; + readonly isAsync: boolean; } class RequestQueue { @@ -672,6 +683,10 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient return undefined; } + public executeAsync(command: string, args: Proto.GeterrRequestArgs, token: CancellationToken): Promise { + return this.executeImpl(command, args, { isAsync: true, token, expectsResult: true }); + } + public execute(command: string, args: any, expectsResultOrToken?: boolean | CancellationToken): Promise { let token: CancellationToken | undefined = undefined; let expectsResult = true; @@ -680,19 +695,23 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient } else { token = expectsResultOrToken; } + return this.executeImpl(command, args, { isAsync: false, token, expectsResult }); + } + private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: CancellationToken, expectsResult: boolean }): Promise { const request = this.requestQueue.createRequest(command, args); const requestInfo: RequestItem = { request: request, - callbacks: null + callbacks: null, + isAsync: executeInfo.isAsync }; let result: Promise; - if (expectsResult) { + if (executeInfo.expectsResult) { let wasCancelled = false; result = new Promise((resolve, reject) => { requestInfo.callbacks = { c: resolve, e: reject, start: Date.now() }; - if (token) { - token.onCancellationRequested(() => { + if (executeInfo.token) { + executeInfo.token.onCancellationRequested(() => { wasCancelled = true; this.tryCancelRequest(request.seq); }); @@ -751,7 +770,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient const serverRequest = requestItem.request; this.tracer.traceRequest(serverRequest, !!requestItem.callbacks, this.requestQueue.length); if (requestItem.callbacks) { - this.callbacks.add(serverRequest.seq, requestItem.callbacks); + this.callbacks.add(serverRequest.seq, requestItem.callbacks, requestItem.isAsync); } this.service() .then((childProcess) => { @@ -820,8 +839,10 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient private dispatchEvent(event: Proto.Event) { switch (event.event) { case 'requestCompleted': - const p = this.callbacks.fetch((event as Proto.RequestCompletedEvent).body.request_seq); + const seq = (event as Proto.RequestCompletedEvent).body.request_seq; + const p = this.callbacks.fetch(seq); if (p) { + this.tracer.traceRequestCompleted('requestCompleted', seq, p.start); p.c(undefined); } break; diff --git a/extensions/typescript-language-features/src/utils/tracer.ts b/extensions/typescript-language-features/src/utils/tracer.ts index 000dd0c4b33bf..97ce34a2abdc3 100644 --- a/extensions/typescript-language-features/src/utils/tracer.ts +++ b/extensions/typescript-language-features/src/utils/tracer.ts @@ -74,6 +74,13 @@ export default class Tracer { this.logTrace(`Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}`, data); } + public traceRequestCompleted(command: string, request_seq: number, startTime: number): any { + if (this.trace === Trace.Off) { + return; + } + this.logTrace(`Async response received: ${command} (${request_seq}). Request took ${Date.now() - startTime} ms.`); + } + public traceEvent(event: Proto.Event): void { if (this.trace === Trace.Off) { return;