Skip to content

Commit

Permalink
Fixes observable related bug (#241195)
Browse files Browse the repository at this point in the history
  • Loading branch information
hediet authored Feb 19, 2025
1 parent e92187f commit a7ba9b9
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 6 deletions.
12 changes: 6 additions & 6 deletions src/vs/base/common/observableInternal/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,10 @@ _setKeepObserved(keepObserved);
export function recomputeInitiallyAndOnChange<T>(observable: IObservable<T>, handleValue?: (value: T) => void): IDisposable {
const o = new KeepAliveObserver(true, handleValue);
observable.addObserver(o);
if (handleValue) {
handleValue(observable.get());
} else {
observable.reportChanges();
try {
o.beginUpdate(observable);
} finally {
o.endUpdate(observable);
}

return toDisposable(() => {
Expand All @@ -447,14 +447,14 @@ export class KeepAliveObserver implements IObserver {
}

endUpdate<T>(observable: IObservable<T>): void {
this._counter--;
if (this._counter === 0 && this._forceRecompute) {
if (this._counter === 1 && this._forceRecompute) {
if (this._handleValue) {
this._handleValue(observable.get());
} else {
observable.reportChanges();
}
}
this._counter--;
}

handlePossibleChange<T>(observable: IObservable<T>): void {
Expand Down
49 changes: 49 additions & 0 deletions src/vs/base/test/common/observable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,55 @@ suite('observables', () => {
});
});

test('recomputeInitiallyAndOnChange should work when a dependency sets an observable', () => {
const store = new DisposableStore();
const log = new Log();

const myObservable = new LoggingObservableValue('myObservable', 0, log);

let shouldUpdate = true;

const myDerived = derived(reader => {
/** @description myDerived */

log.log('myDerived.computed start');

const val = myObservable.read(reader);

if (shouldUpdate) {
shouldUpdate = false;
myObservable.set(1, undefined);
}

log.log('myDerived.computed end');

return val;
});

assert.deepStrictEqual(log.getAndClearEntries(), ([]));

myDerived.recomputeInitiallyAndOnChange(store, val => {
log.log(`recomputeInitiallyAndOnChange, myDerived: ${val}`);
});

assert.deepStrictEqual(log.getAndClearEntries(), [
"myDerived.computed start",
"myObservable.firstObserverAdded",
"myObservable.get",
"myObservable.set (value 1)",
"myDerived.computed end",
"myDerived.computed start",
"myObservable.get",
"myDerived.computed end",
"recomputeInitiallyAndOnChange, myDerived: 1",
]);

myDerived.get();
assert.deepStrictEqual(log.getAndClearEntries(), ([]));

store.dispose();
});

suite('prevent invalid usage', () => {
suite('reading outside of compute function', () => {
test('derived', () => {
Expand Down

0 comments on commit a7ba9b9

Please sign in to comment.