mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Merge from master
This commit is contained in:
@@ -3,35 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { TPromise, ValueCallback, ErrorCallback, ProgressCallback } from 'vs/base/common/winjs.base';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export function isThenable<T>(obj: any): obj is Thenable<T> {
|
||||
return obj && typeof (<Thenable<any>>obj).then === 'function';
|
||||
}
|
||||
|
||||
export function toThenable<T>(arg: T | Thenable<T>): Thenable<T> {
|
||||
if (isThenable(arg)) {
|
||||
return arg;
|
||||
} else {
|
||||
return TPromise.as(arg);
|
||||
}
|
||||
}
|
||||
|
||||
export function toWinJsPromise<T>(arg: Thenable<T> | TPromise<T>): TPromise<T> {
|
||||
if (arg instanceof TPromise) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
return new TPromise((resolve, reject) => arg.then(resolve, reject));
|
||||
}
|
||||
|
||||
export interface CancelablePromise<T> extends Promise<T> {
|
||||
cancel(): void;
|
||||
}
|
||||
@@ -66,78 +47,17 @@ export function createCancelablePromise<T>(callback: (token: CancellationToken)
|
||||
};
|
||||
}
|
||||
|
||||
export function asWinJsPromise<T>(callback: (token: CancellationToken) => T | TPromise<T> | Thenable<T>): TPromise<T> {
|
||||
let source = new CancellationTokenSource();
|
||||
return new TPromise<T>((resolve, reject, progress) => {
|
||||
let item = callback(source.token);
|
||||
if (item instanceof TPromise) {
|
||||
item.then(result => {
|
||||
source.dispose();
|
||||
resolve(result);
|
||||
}, err => {
|
||||
source.dispose();
|
||||
reject(err);
|
||||
}, progress);
|
||||
} else if (isThenable<T>(item)) {
|
||||
item.then(result => {
|
||||
source.dispose();
|
||||
resolve(result);
|
||||
}, err => {
|
||||
source.dispose();
|
||||
reject(err);
|
||||
});
|
||||
export function asThenable<T>(callback: () => T | Thenable<T>): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
let item = callback();
|
||||
if (isThenable<T>(item)) {
|
||||
item.then(resolve, reject);
|
||||
} else {
|
||||
source.dispose();
|
||||
resolve(item);
|
||||
}
|
||||
}, () => {
|
||||
source.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook a cancellation token to a WinJS Promise
|
||||
*/
|
||||
export function wireCancellationToken<T>(token: CancellationToken, promise: TPromise<T>, resolveAsUndefinedWhenCancelled?: boolean): Thenable<T> {
|
||||
const subscription = token.onCancellationRequested(() => promise.cancel());
|
||||
if (resolveAsUndefinedWhenCancelled) {
|
||||
promise = promise.then<T>(undefined, err => {
|
||||
if (!errors.isPromiseCanceledError(err)) {
|
||||
return TPromise.wrapError(err);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
return always(promise, () => subscription.dispose());
|
||||
}
|
||||
|
||||
export function asDisposablePromise<T>(input: Thenable<T>, cancelValue?: T, bucket?: IDisposable[]): { promise: Thenable<T> } & IDisposable {
|
||||
let dispose: () => void;
|
||||
let promise = new TPromise((resolve, reject) => {
|
||||
dispose = function () {
|
||||
resolve(cancelValue);
|
||||
if (isWinJSPromise(input)) {
|
||||
input.cancel();
|
||||
}
|
||||
};
|
||||
input.then(resolve, err => {
|
||||
if (errors.isPromiseCanceledError(err)) {
|
||||
resolve(cancelValue);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
let res = {
|
||||
promise,
|
||||
dispose
|
||||
};
|
||||
if (Array.isArray(bucket)) {
|
||||
bucket.push(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export interface ITask<T> {
|
||||
(): T;
|
||||
}
|
||||
@@ -170,9 +90,9 @@ export interface ITask<T> {
|
||||
*/
|
||||
export class Throttler {
|
||||
|
||||
private activePromise: TPromise;
|
||||
private queuedPromise: TPromise;
|
||||
private queuedPromiseFactory: ITask<TPromise>;
|
||||
private activePromise: Thenable<any> | null;
|
||||
private queuedPromise: Thenable<any> | null;
|
||||
private queuedPromiseFactory: ITask<Thenable<any>> | null;
|
||||
|
||||
constructor() {
|
||||
this.activePromise = null;
|
||||
@@ -180,7 +100,7 @@ export class Throttler {
|
||||
this.queuedPromiseFactory = null;
|
||||
}
|
||||
|
||||
queue<T>(promiseFactory: ITask<TPromise<T>>): TPromise<T> {
|
||||
queue<T>(promiseFactory: ITask<Thenable<T>>): Thenable<T> {
|
||||
if (this.activePromise) {
|
||||
this.queuedPromiseFactory = promiseFactory;
|
||||
|
||||
@@ -188,48 +108,41 @@ export class Throttler {
|
||||
const onComplete = () => {
|
||||
this.queuedPromise = null;
|
||||
|
||||
const result = this.queue(this.queuedPromiseFactory);
|
||||
const result = this.queue(this.queuedPromiseFactory!);
|
||||
this.queuedPromiseFactory = null;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
this.queuedPromise = new TPromise((c, e, p) => {
|
||||
this.activePromise.then(onComplete, onComplete, p).done(c);
|
||||
}, () => {
|
||||
this.activePromise.cancel();
|
||||
this.queuedPromise = new Promise(c => {
|
||||
this.activePromise!.then(onComplete, onComplete).then(c);
|
||||
});
|
||||
}
|
||||
|
||||
return new TPromise((c, e, p) => {
|
||||
this.queuedPromise.then(c, e, p);
|
||||
}, () => {
|
||||
// no-op
|
||||
return new Promise((c, e) => {
|
||||
this.queuedPromise!.then(c, e);
|
||||
});
|
||||
}
|
||||
|
||||
this.activePromise = promiseFactory();
|
||||
|
||||
return new TPromise((c, e, p) => {
|
||||
this.activePromise.done((result: any) => {
|
||||
return new Promise((c, e) => {
|
||||
this.activePromise!.then((result: any) => {
|
||||
this.activePromise = null;
|
||||
c(result);
|
||||
}, (err: any) => {
|
||||
this.activePromise = null;
|
||||
e(err);
|
||||
}, p);
|
||||
}, () => {
|
||||
this.activePromise.cancel();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO@Joao: can the previous throttler be replaced with this?
|
||||
export class SimpleThrottler {
|
||||
export class Sequencer {
|
||||
|
||||
private current = TPromise.wrap<any>(null);
|
||||
private current: Promise<any> = Promise.resolve(null);
|
||||
|
||||
queue<T>(promiseTask: ITask<TPromise<T>>): TPromise<T> {
|
||||
queue<T>(promiseTask: ITask<Thenable<T>>): Thenable<T> {
|
||||
return this.current = this.current.then(() => promiseTask());
|
||||
}
|
||||
}
|
||||
@@ -257,33 +170,33 @@ export class SimpleThrottler {
|
||||
* delayer.trigger(() => { return makeTheTrip(); });
|
||||
* }
|
||||
*/
|
||||
export class Delayer<T> {
|
||||
export class Delayer<T> implements IDisposable {
|
||||
|
||||
private timeout: number;
|
||||
private completionPromise: TPromise;
|
||||
private onSuccess: ValueCallback;
|
||||
private task: ITask<T | TPromise<T>>;
|
||||
private timeout: any;
|
||||
private completionPromise: Thenable<any> | null;
|
||||
private doResolve: ((value?: any | Thenable<any>) => void) | null;
|
||||
private doReject: (err: any) => void;
|
||||
private task: ITask<T | Thenable<T>> | null;
|
||||
|
||||
constructor(public defaultDelay: number) {
|
||||
this.timeout = null;
|
||||
this.completionPromise = null;
|
||||
this.onSuccess = null;
|
||||
this.doResolve = null;
|
||||
this.task = null;
|
||||
}
|
||||
|
||||
trigger(task: ITask<T | TPromise<T>>, delay: number = this.defaultDelay): TPromise<T> {
|
||||
trigger(task: ITask<T | Thenable<T>>, delay: number = this.defaultDelay): Thenable<T> {
|
||||
this.task = task;
|
||||
this.cancelTimeout();
|
||||
|
||||
if (!this.completionPromise) {
|
||||
this.completionPromise = new TPromise((c) => {
|
||||
this.onSuccess = c;
|
||||
}, () => {
|
||||
// no-op
|
||||
this.completionPromise = new Promise((c, e) => {
|
||||
this.doResolve = c;
|
||||
this.doReject = e;
|
||||
}).then(() => {
|
||||
this.completionPromise = null;
|
||||
this.onSuccess = null;
|
||||
const task = this.task;
|
||||
this.doResolve = null;
|
||||
const task = this.task!;
|
||||
this.task = null;
|
||||
|
||||
return task();
|
||||
@@ -292,7 +205,7 @@ export class Delayer<T> {
|
||||
|
||||
this.timeout = setTimeout(() => {
|
||||
this.timeout = null;
|
||||
this.onSuccess(null);
|
||||
this.doResolve!(null);
|
||||
}, delay);
|
||||
|
||||
return this.completionPromise;
|
||||
@@ -306,7 +219,7 @@ export class Delayer<T> {
|
||||
this.cancelTimeout();
|
||||
|
||||
if (this.completionPromise) {
|
||||
this.completionPromise.cancel();
|
||||
this.doReject(errors.canceled());
|
||||
this.completionPromise = null;
|
||||
}
|
||||
}
|
||||
@@ -317,27 +230,45 @@ export class Delayer<T> {
|
||||
this.timeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.cancelTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to delay execution of a task that is being requested often, while
|
||||
* preventing accumulation of consecutive executions, while the task runs.
|
||||
*
|
||||
* Simply combine the two mail men's strategies from the Throttler and Delayer
|
||||
* helpers, for an analogy.
|
||||
* The mail man is clever and waits for a certain amount of time, before going
|
||||
* out to deliver letters. While the mail man is going out, more letters arrive
|
||||
* and can only be delivered once he is back. Once he is back the mail man will
|
||||
* do one more trip to deliver the letters that have accumulated while he was out.
|
||||
*/
|
||||
export class ThrottledDelayer<T> extends Delayer<TPromise<T>> {
|
||||
export class ThrottledDelayer<T> {
|
||||
|
||||
private delayer: Delayer<Thenable<T>>;
|
||||
private throttler: Throttler;
|
||||
|
||||
constructor(defaultDelay: number) {
|
||||
super(defaultDelay);
|
||||
|
||||
this.delayer = new Delayer(defaultDelay);
|
||||
this.throttler = new Throttler();
|
||||
}
|
||||
|
||||
trigger(promiseFactory: ITask<TPromise<T>>, delay?: number): TPromise {
|
||||
return super.trigger(() => this.throttler.queue(promiseFactory), delay);
|
||||
trigger(promiseFactory: ITask<Thenable<T>>, delay?: number): Thenable<T> {
|
||||
return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as any as Thenable<T>;
|
||||
}
|
||||
|
||||
isTriggered(): boolean {
|
||||
return this.delayer.isTriggered();
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
this.delayer.cancel();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.delayer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,15 +278,13 @@ export class ThrottledDelayer<T> extends Delayer<TPromise<T>> {
|
||||
export class Barrier {
|
||||
|
||||
private _isOpen: boolean;
|
||||
private _promise: TPromise<boolean>;
|
||||
private _promise: Promise<boolean>;
|
||||
private _completePromise: (v: boolean) => void;
|
||||
|
||||
constructor() {
|
||||
this._isOpen = false;
|
||||
this._promise = new TPromise<boolean>((c, e) => {
|
||||
this._promise = new Promise<boolean>((c, e) => {
|
||||
this._completePromise = c;
|
||||
}, () => {
|
||||
console.warn('You should really not try to cancel this ready promise!');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -368,50 +297,34 @@ export class Barrier {
|
||||
this._completePromise(true);
|
||||
}
|
||||
|
||||
wait(): TPromise<boolean> {
|
||||
wait(): Promise<boolean> {
|
||||
return this._promise;
|
||||
}
|
||||
}
|
||||
|
||||
export class ShallowCancelThenPromise<T> extends TPromise<T> {
|
||||
|
||||
constructor(outer: TPromise<T>) {
|
||||
|
||||
let completeCallback: ValueCallback,
|
||||
errorCallback: ErrorCallback,
|
||||
progressCallback: ProgressCallback;
|
||||
|
||||
super((c, e, p) => {
|
||||
completeCallback = c;
|
||||
errorCallback = e;
|
||||
progressCallback = p;
|
||||
}, () => {
|
||||
// cancel this promise but not the
|
||||
// outer promise
|
||||
errorCallback(errors.canceled());
|
||||
});
|
||||
|
||||
outer.then(completeCallback, errorCallback, progressCallback);
|
||||
export function timeout(millis: number): CancelablePromise<void>;
|
||||
export function timeout(millis: number, token: CancellationToken): Thenable<void>;
|
||||
export function timeout(millis: number, token?: CancellationToken): CancelablePromise<void> | Thenable<void> {
|
||||
if (!token) {
|
||||
return createCancelablePromise(token => timeout(millis, token));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for `WinJS.TPromise.timeout`.
|
||||
*/
|
||||
export function timeout(n: number): CancelablePromise<void> {
|
||||
return createCancelablePromise(token => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const handle = setTimeout(resolve, n);
|
||||
token.onCancellationRequested(_ => {
|
||||
clearTimeout(handle);
|
||||
reject(errors.canceled());
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
const handle = setTimeout(resolve, millis);
|
||||
token.onCancellationRequested(() => {
|
||||
clearTimeout(handle);
|
||||
reject(errors.canceled());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isWinJSPromise(candidate: any): candidate is TPromise {
|
||||
return TPromise.is(candidate) && typeof (<TPromise>candidate).done === 'function';
|
||||
export function disposableTimeout(handler: Function, timeout = 0): IDisposable {
|
||||
const timer = setTimeout(handler, timeout);
|
||||
return {
|
||||
dispose() {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -419,39 +332,22 @@ function isWinJSPromise(candidate: any): candidate is TPromise {
|
||||
* the provided promise the provided function will always be called. This
|
||||
* method is comparable to a try-finally code block.
|
||||
* @param promise a promise
|
||||
* @param f a function that will be call in the success and error case.
|
||||
* @param callback a function that will be call in the success and error case.
|
||||
*/
|
||||
export function always<T>(thenable: TPromise<T>, f: Function): TPromise<T>;
|
||||
export function always<T>(promise: Thenable<T>, f: Function): Thenable<T>;
|
||||
export function always<T>(winjsPromiseOrThenable: Thenable<T> | TPromise<T>, f: Function): TPromise<T> | Thenable<T> {
|
||||
if (isWinJSPromise(winjsPromiseOrThenable)) {
|
||||
return new TPromise<T>((c, e, p) => {
|
||||
winjsPromiseOrThenable.done((result) => {
|
||||
try {
|
||||
f(result);
|
||||
} catch (e1) {
|
||||
errors.onUnexpectedError(e1);
|
||||
}
|
||||
c(result);
|
||||
}, (err) => {
|
||||
try {
|
||||
f(err);
|
||||
} catch (e1) {
|
||||
errors.onUnexpectedError(e1);
|
||||
}
|
||||
e(err);
|
||||
}, (progress) => {
|
||||
p(progress);
|
||||
});
|
||||
}, () => {
|
||||
winjsPromiseOrThenable.cancel();
|
||||
});
|
||||
|
||||
} else {
|
||||
// simple
|
||||
winjsPromiseOrThenable.then(_ => f(), _ => f());
|
||||
return winjsPromiseOrThenable;
|
||||
export function always<T>(promise: Thenable<T>, callback: () => void): Promise<T> {
|
||||
function safeCallback() {
|
||||
try {
|
||||
callback();
|
||||
} catch (err) {
|
||||
errors.onUnexpectedError(err);
|
||||
}
|
||||
}
|
||||
promise.then(_ => safeCallback(), _ => safeCallback());
|
||||
return Promise.resolve(promise);
|
||||
}
|
||||
|
||||
export function ignoreErrors<T>(promise: Thenable<T>): Thenable<T | undefined> {
|
||||
return promise.then(undefined, _ => undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -459,7 +355,7 @@ export function always<T>(winjsPromiseOrThenable: Thenable<T> | TPromise<T>, f:
|
||||
* promise will complete to an array of results from each promise.
|
||||
*/
|
||||
|
||||
export function sequence<T>(promiseFactories: ITask<Thenable<T>>[]): TPromise<T[]> {
|
||||
export function sequence<T>(promiseFactories: ITask<Thenable<T>>[]): Promise<T[]> {
|
||||
const results: T[] = [];
|
||||
let index = 0;
|
||||
const len = promiseFactories.length;
|
||||
@@ -478,50 +374,28 @@ export function sequence<T>(promiseFactories: ITask<Thenable<T>>[]): TPromise<T[
|
||||
return n.then(thenHandler);
|
||||
}
|
||||
|
||||
return TPromise.as(results);
|
||||
return Promise.resolve(results);
|
||||
}
|
||||
|
||||
return TPromise.as(null).then(thenHandler);
|
||||
return Promise.resolve(null).then(thenHandler);
|
||||
}
|
||||
|
||||
export function first2<T>(promiseFactories: ITask<Promise<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T = null): Promise<T> {
|
||||
|
||||
export function first<T>(promiseFactories: ITask<Thenable<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null): Promise<T | null> {
|
||||
let index = 0;
|
||||
const len = promiseFactories.length;
|
||||
|
||||
const loop = () => {
|
||||
const loop: () => Promise<T | null> = () => {
|
||||
if (index >= len) {
|
||||
return Promise.resolve(defaultValue);
|
||||
}
|
||||
|
||||
const factory = promiseFactories[index++];
|
||||
const promise = factory();
|
||||
const promise = Promise.resolve(factory());
|
||||
|
||||
return promise.then(result => {
|
||||
if (shouldStop(result)) {
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
return loop();
|
||||
});
|
||||
};
|
||||
|
||||
return loop();
|
||||
}
|
||||
|
||||
export function first<T>(promiseFactories: ITask<TPromise<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T = null): TPromise<T> {
|
||||
let index = 0;
|
||||
const len = promiseFactories.length;
|
||||
|
||||
const loop: () => TPromise<T> = () => {
|
||||
if (index >= len) {
|
||||
return TPromise.as(defaultValue);
|
||||
}
|
||||
|
||||
const factory = promiseFactories[index++];
|
||||
const promise = factory();
|
||||
|
||||
return promise.then(result => {
|
||||
if (shouldStop(result)) {
|
||||
return TPromise.as(result);
|
||||
}
|
||||
|
||||
return loop();
|
||||
});
|
||||
@@ -530,11 +404,10 @@ export function first<T>(promiseFactories: ITask<TPromise<T>>[], shouldStop: (t:
|
||||
return loop();
|
||||
}
|
||||
|
||||
interface ILimitedTaskFactory {
|
||||
factory: ITask<TPromise>;
|
||||
c: ValueCallback;
|
||||
e: ErrorCallback;
|
||||
p: ProgressCallback;
|
||||
interface ILimitedTaskFactory<T> {
|
||||
factory: ITask<Thenable<T>>;
|
||||
c: (value?: T | Thenable<T>) => void;
|
||||
e: (error?: any) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -542,9 +415,11 @@ interface ILimitedTaskFactory {
|
||||
* ensures that at any time no more than M promises are running at the same time.
|
||||
*/
|
||||
export class Limiter<T> {
|
||||
|
||||
private _size = 0;
|
||||
private runningPromises: number;
|
||||
private maxDegreeOfParalellism: number;
|
||||
private outstandingPromises: ILimitedTaskFactory[];
|
||||
private outstandingPromises: ILimitedTaskFactory<T>[];
|
||||
private readonly _onFinished: Emitter<void>;
|
||||
|
||||
constructor(maxDegreeOfParalellism: number) {
|
||||
@@ -559,35 +434,32 @@ export class Limiter<T> {
|
||||
}
|
||||
|
||||
public get size(): number {
|
||||
return this.runningPromises + this.outstandingPromises.length;
|
||||
return this._size;
|
||||
// return this.runningPromises + this.outstandingPromises.length;
|
||||
}
|
||||
|
||||
queue(promiseFactory: ITask<TPromise>): TPromise;
|
||||
queue(promiseFactory: ITask<TPromise<T>>): TPromise<T> {
|
||||
return new TPromise<T>((c, e, p) => {
|
||||
this.outstandingPromises.push({
|
||||
factory: promiseFactory,
|
||||
c: c,
|
||||
e: e,
|
||||
p: p
|
||||
});
|
||||
queue(factory: ITask<Thenable<T>>): Thenable<T> {
|
||||
this._size++;
|
||||
|
||||
return new Promise<T>((c, e) => {
|
||||
this.outstandingPromises.push({ factory, c, e });
|
||||
this.consume();
|
||||
});
|
||||
}
|
||||
|
||||
private consume(): void {
|
||||
while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) {
|
||||
const iLimitedTask = this.outstandingPromises.shift();
|
||||
const iLimitedTask = this.outstandingPromises.shift()!;
|
||||
this.runningPromises++;
|
||||
|
||||
const promise = iLimitedTask.factory();
|
||||
promise.done(iLimitedTask.c, iLimitedTask.e, iLimitedTask.p);
|
||||
promise.done(() => this.consumed(), () => this.consumed());
|
||||
promise.then(iLimitedTask.c, iLimitedTask.e);
|
||||
promise.then(() => this.consumed(), () => this.consumed());
|
||||
}
|
||||
}
|
||||
|
||||
private consumed(): void {
|
||||
this._size--;
|
||||
this.runningPromises--;
|
||||
|
||||
if (this.outstandingPromises.length > 0) {
|
||||
@@ -639,17 +511,18 @@ export class ResourceQueue {
|
||||
}
|
||||
}
|
||||
|
||||
export function setDisposableTimeout(handler: Function, timeout: number, ...args: any[]): IDisposable {
|
||||
const handle = setTimeout(handler, timeout, ...args);
|
||||
return { dispose() { clearTimeout(handle); } };
|
||||
}
|
||||
|
||||
export class TimeoutTimer extends Disposable {
|
||||
private _token: number;
|
||||
private _token: any;
|
||||
|
||||
constructor() {
|
||||
constructor();
|
||||
constructor(runner: () => void, timeout: number);
|
||||
constructor(runner?: () => void, timeout?: number) {
|
||||
super();
|
||||
this._token = -1;
|
||||
|
||||
if (typeof runner === 'function' && typeof timeout === 'number') {
|
||||
this.setIfNotSet(runner, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -686,7 +559,7 @@ export class TimeoutTimer extends Disposable {
|
||||
|
||||
export class IntervalTimer extends Disposable {
|
||||
|
||||
private _token: number;
|
||||
private _token: any;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -715,9 +588,9 @@ export class IntervalTimer extends Disposable {
|
||||
|
||||
export class RunOnceScheduler {
|
||||
|
||||
protected runner: (...args: any[]) => void;
|
||||
protected runner: ((...args: any[]) => void) | null;
|
||||
|
||||
private timeoutToken: number;
|
||||
private timeoutToken: any;
|
||||
private timeout: number;
|
||||
private timeoutHandler: () => void;
|
||||
|
||||
@@ -769,7 +642,9 @@ export class RunOnceScheduler {
|
||||
}
|
||||
|
||||
protected doRun(): void {
|
||||
this.runner();
|
||||
if (this.runner) {
|
||||
this.runner();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,7 +667,9 @@ export class RunOnceWorker<T> extends RunOnceScheduler {
|
||||
const units = this.units;
|
||||
this.units = [];
|
||||
|
||||
this.runner(units);
|
||||
if (this.runner) {
|
||||
this.runner(units);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -802,14 +679,109 @@ export class RunOnceWorker<T> extends RunOnceScheduler {
|
||||
}
|
||||
}
|
||||
|
||||
export function nfcall(fn: Function, ...args: any[]): TPromise;
|
||||
export function nfcall<T>(fn: Function, ...args: any[]): TPromise<T>;
|
||||
export function nfcall(fn: Function, ...args: any[]): Promise<any>;
|
||||
export function nfcall<T>(fn: Function, ...args: any[]): Promise<T>;
|
||||
export function nfcall(fn: Function, ...args: any[]): any {
|
||||
return new TPromise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)), () => null);
|
||||
return new Promise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)));
|
||||
}
|
||||
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): TPromise;
|
||||
export function ninvoke<T>(thisArg: any, fn: Function, ...args: any[]): TPromise<T>;
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Thenable<any>;
|
||||
export function ninvoke<T>(thisArg: any, fn: Function, ...args: any[]): Thenable<T>;
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): any {
|
||||
return new TPromise((c, e) => fn.call(thisArg, ...args, (err: any, result: any) => err ? e(err) : c(result)), () => null);
|
||||
return new Promise((resolve, reject) => fn.call(thisArg, ...args, (err: any, result: any) => err ? reject(err) : resolve(result)));
|
||||
}
|
||||
|
||||
|
||||
//#region -- run on idle tricks ------------
|
||||
|
||||
export interface IdleDeadline {
|
||||
readonly didTimeout: boolean;
|
||||
timeRemaining(): DOMHighResTimeStamp;
|
||||
}
|
||||
/**
|
||||
* Execute the callback the next time the browser is idle
|
||||
*/
|
||||
export let runWhenIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;
|
||||
|
||||
declare function requestIdleCallback(callback: (args: IdleDeadline) => void, options?: { timeout: number }): number;
|
||||
declare function cancelIdleCallback(handle: number): void;
|
||||
|
||||
(function () {
|
||||
if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') {
|
||||
let dummyIdle: IdleDeadline = Object.freeze({
|
||||
didTimeout: true,
|
||||
timeRemaining() { return 15; }
|
||||
});
|
||||
runWhenIdle = (runner, timeout = 0) => {
|
||||
let handle = setTimeout(() => runner(dummyIdle), timeout);
|
||||
let disposed = false;
|
||||
return {
|
||||
dispose() {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
clearTimeout(handle);
|
||||
}
|
||||
};
|
||||
};
|
||||
} else {
|
||||
runWhenIdle = (runner, timeout?) => {
|
||||
let handle: number = requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined);
|
||||
let disposed = false;
|
||||
return {
|
||||
dispose() {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
cancelIdleCallback(handle);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* An implementation of the "idle-until-urgent"-strategy as introduced
|
||||
* here: https://philipwalton.com/articles/idle-until-urgent/
|
||||
*/
|
||||
export class IdleValue<T> {
|
||||
|
||||
private readonly _executor: () => void;
|
||||
private readonly _handle: IDisposable;
|
||||
|
||||
private _didRun: boolean;
|
||||
private _value: T;
|
||||
private _error: any;
|
||||
|
||||
constructor(executor: () => T) {
|
||||
this._executor = () => {
|
||||
try {
|
||||
this._value = executor();
|
||||
} catch (err) {
|
||||
this._error = err;
|
||||
} finally {
|
||||
this._didRun = true;
|
||||
}
|
||||
};
|
||||
this._handle = runWhenIdle(() => this._executor());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._handle.dispose();
|
||||
}
|
||||
|
||||
getValue(): T {
|
||||
if (!this._didRun) {
|
||||
this._handle.dispose();
|
||||
this._executor();
|
||||
}
|
||||
if (this._error) {
|
||||
throw this._error;
|
||||
}
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
Reference in New Issue
Block a user