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