Path: blob/main/extensions/microsoft-authentication/src/common/async.ts
3320 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { CancellationError, CancellationToken, Disposable, Event } from 'vscode';67export class SequencerByKey<TKey> {89private promiseMap = new Map<TKey, Promise<unknown>>();1011queue<T>(key: TKey, promiseTask: () => Promise<T>): Promise<T> {12const runningPromise = this.promiseMap.get(key) ?? Promise.resolve();13const newPromise = runningPromise14.catch(() => { })15.then(promiseTask)16.finally(() => {17if (this.promiseMap.get(key) === newPromise) {18this.promiseMap.delete(key);19}20});21this.promiseMap.set(key, newPromise);22return newPromise;23}24}2526export class IntervalTimer extends Disposable {2728private _token: any;2930constructor() {31super(() => this.cancel());32this._token = -1;33}3435cancel(): void {36if (this._token !== -1) {37clearInterval(this._token);38this._token = -1;39}40}4142cancelAndSet(runner: () => void, interval: number): void {43this.cancel();44this._token = setInterval(() => {45runner();46}, interval);47}48}4950/**51* Returns a promise that rejects with an {@CancellationError} as soon as the passed token is cancelled.52* @see {@link raceCancellation}53*/54function raceCancellationError<T>(promise: Promise<T>, token: CancellationToken): Promise<T> {55return new Promise((resolve, reject) => {56const ref = token.onCancellationRequested(() => {57ref.dispose();58reject(new CancellationError());59});60promise.then(resolve, reject).finally(() => ref.dispose());61});62}6364function raceTimeoutError<T>(promise: Promise<T>, timeout: number): Promise<T> {65return new Promise((resolve, reject) => {66const ref = setTimeout(() => {67reject(new CancellationError());68}, timeout);69promise.then(resolve, reject).finally(() => clearTimeout(ref));70});71}7273export function raceCancellationAndTimeoutError<T>(promise: Promise<T>, token: CancellationToken, timeout: number): Promise<T> {74return raceCancellationError(raceTimeoutError(promise, timeout), token);75}7677/**78* Given an event, returns another event which only fires once.79*80* @param event The event source for the new event.81*/82function once<T>(event: Event<T>): Event<T> {83return (listener, thisArgs = null, disposables?) => {84// we need this, in case the event fires during the listener call85let didFire = false;86let result: Disposable | undefined = undefined;87result = event(e => {88if (didFire) {89return;90} else if (result) {91result.dispose();92} else {93didFire = true;94}9596return listener.call(thisArgs, e);97}, null, disposables);9899if (didFire) {100result.dispose();101}102103return result;104};105}106107/**108* Creates a promise out of an event, using the {@link Event.once} helper.109*/110export function toPromise<T>(event: Event<T>): Promise<T> {111return new Promise(resolve => once(event)(resolve));112}113114//#region DeferredPromise115116export type ValueCallback<T = unknown> = (value: T | Promise<T>) => void;117118const enum DeferredOutcome {119Resolved,120Rejected121}122123/**124* Creates a promise whose resolution or rejection can be controlled imperatively.125*/126export class DeferredPromise<T> {127128private completeCallback!: ValueCallback<T>;129private errorCallback!: (err: unknown) => void;130private outcome?: { outcome: DeferredOutcome.Rejected; value: any } | { outcome: DeferredOutcome.Resolved; value: T };131132public get isRejected() {133return this.outcome?.outcome === DeferredOutcome.Rejected;134}135136public get isResolved() {137return this.outcome?.outcome === DeferredOutcome.Resolved;138}139140public get isSettled() {141return !!this.outcome;142}143144public get value() {145return this.outcome?.outcome === DeferredOutcome.Resolved ? this.outcome?.value : undefined;146}147148public readonly p: Promise<T>;149150constructor() {151this.p = new Promise<T>((c, e) => {152this.completeCallback = c;153this.errorCallback = e;154});155}156157public complete(value: T) {158return new Promise<void>(resolve => {159this.completeCallback(value);160this.outcome = { outcome: DeferredOutcome.Resolved, value };161resolve();162});163}164165public error(err: unknown) {166return new Promise<void>(resolve => {167this.errorCallback(err);168this.outcome = { outcome: DeferredOutcome.Rejected, value: err };169resolve();170});171}172173public cancel() {174return this.error(new CancellationError());175}176}177178//#endregion179180181