Path: blob/main/extensions/copilot/src/util/vs/base/common/observableInternal/transaction.ts
13406 views
//!!! DO NOT modify, this file was COPIED from 'microsoft/vscode'12/*---------------------------------------------------------------------------------------------3* Copyright (c) Microsoft Corporation. All rights reserved.4* Licensed under the MIT License. See License.txt in the project root for license information.5*--------------------------------------------------------------------------------------------*/67import { handleBugIndicatingErrorRecovery, IObservable, IObserver, ITransaction } from './base';8import { getFunctionName } from './debugName';9import { getLogger } from './logging/logging';1011/**12* Starts a transaction in which many observables can be changed at once.13* {@link fn} should start with a JS Doc using `@description` to give the transaction a debug name.14* Reaction run on demand or when the transaction ends.15*/1617export function transaction(fn: (tx: ITransaction) => void, getDebugName?: () => string): void {18const tx = new TransactionImpl(fn, getDebugName);19try {20fn(tx);21} finally {22tx.finish();23}24}25let _globalTransaction: ITransaction | undefined = undefined;2627export function globalTransaction(fn: (tx: ITransaction) => void) {28if (_globalTransaction) {29fn(_globalTransaction);30} else {31const tx = new TransactionImpl(fn, undefined);32_globalTransaction = tx;33try {34fn(tx);35} finally {36tx.finish(); // During finish, more actions might be added to the transaction.3738// Which is why we only clear the global transaction after finish.39_globalTransaction = undefined;40}41}42}43/** @deprecated */4445export async function asyncTransaction(fn: (tx: ITransaction) => Promise<void>, getDebugName?: () => string): Promise<void> {46const tx = new TransactionImpl(fn, getDebugName);47try {48await fn(tx);49} finally {50tx.finish();51}52}53/**54* Allows to chain transactions.55*/5657export function subtransaction(tx: ITransaction | undefined, fn: (tx: ITransaction) => void, getDebugName?: () => string): void {58if (!tx) {59transaction(fn, getDebugName);60} else {61fn(tx);62}63} export class TransactionImpl implements ITransaction {64private _updatingObservers: { observer: IObserver; observable: IObservable<any> }[] | null = [];6566constructor(public readonly _fn: Function, private readonly _getDebugName?: () => string) {67getLogger()?.handleBeginTransaction(this);68}6970public getDebugName(): string | undefined {71if (this._getDebugName) {72return this._getDebugName();73}74return getFunctionName(this._fn);75}7677public updateObserver(observer: IObserver, observable: IObservable<any>): void {78if (!this._updatingObservers) {79// This happens when a transaction is used in a callback or async function.80// If an async transaction is used, make sure the promise awaits all users of the transaction (e.g. no race).81handleBugIndicatingErrorRecovery('Transaction already finished!');82// Error recovery83transaction(tx => {84tx.updateObserver(observer, observable);85});86return;87}8889// When this gets called while finish is active, they will still get considered90this._updatingObservers.push({ observer, observable });91observer.beginUpdate(observable);92}9394public finish(): void {95const updatingObservers = this._updatingObservers;96if (!updatingObservers) {97handleBugIndicatingErrorRecovery('transaction.finish() has already been called!');98return;99}100101for (let i = 0; i < updatingObservers.length; i++) {102const { observer, observable } = updatingObservers[i];103observer.endUpdate(observable);104}105// Prevent anyone from updating observers from now on.106this._updatingObservers = null;107getLogger()?.handleEndTransaction(this);108}109110public debugGetUpdatingObservers() {111return this._updatingObservers;112}113}114115116117