monaco-editor-core
Version:
A browser based code editor
106 lines (105 loc) • 3.5 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { autorun } from './autorun.js';
import { observableValue, transaction } from './base.js';
import { CancellationError } from '../errors.js';
/**
* A promise whose state is observable.
*/
export class ObservablePromise {
static fromFn(fn) {
return new ObservablePromise(fn());
}
constructor(promise) {
this._value = observableValue(this, undefined);
/**
* The current state of the promise.
* Is `undefined` if the promise didn't resolve yet.
*/
this.promiseResult = this._value;
this.promise = promise.then(value => {
transaction(tx => {
/** @description onPromiseResolved */
this._value.set(new PromiseResult(value, undefined), tx);
});
return value;
}, error => {
transaction(tx => {
/** @description onPromiseRejected */
this._value.set(new PromiseResult(undefined, error), tx);
});
throw error;
});
}
}
export class PromiseResult {
constructor(
/**
* The value of the resolved promise.
* Undefined if the promise rejected.
*/
data,
/**
* The error in case of a rejected promise.
* Undefined if the promise resolved.
*/
error) {
this.data = data;
this.error = error;
}
}
export function waitForState(observable, predicate, isError, cancellationToken) {
if (!predicate) {
predicate = state => state !== null && state !== undefined;
}
return new Promise((resolve, reject) => {
let isImmediateRun = true;
let shouldDispose = false;
const stateObs = observable.map(state => {
/** @description waitForState.state */
return {
isFinished: predicate(state),
error: isError ? isError(state) : false,
state
};
});
const d = autorun(reader => {
/** @description waitForState */
const { isFinished, error, state } = stateObs.read(reader);
if (isFinished || error) {
if (isImmediateRun) {
// The variable `d` is not initialized yet
shouldDispose = true;
}
else {
d.dispose();
}
if (error) {
reject(error === true ? state : error);
}
else {
resolve(state);
}
}
});
if (cancellationToken) {
const dc = cancellationToken.onCancellationRequested(() => {
d.dispose();
dc.dispose();
reject(new CancellationError());
});
if (cancellationToken.isCancellationRequested) {
d.dispose();
dc.dispose();
reject(new CancellationError());
return;
}
}
isImmediateRun = false;
if (shouldDispose) {
d.dispose();
}
});
}