Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6aabe91
Added tasts
mszylkowski Dec 21, 2021
dc1fa87
Undo
mszylkowski Dec 21, 2021
d707e5b
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Dec 28, 2021
0e3df75
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Dec 28, 2021
a3f7bd0
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Jan 4, 2022
8c5119c
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Jan 6, 2022
77f8435
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Jan 10, 2022
16e712e
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Jan 19, 2022
8088eb7
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Jan 25, 2022
3858b2a
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Jan 28, 2022
e12d2f6
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Jan 31, 2022
2a29105
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Feb 1, 2022
a5b781f
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Feb 10, 2022
b8006ee
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Mar 8, 2022
b570e86
Merge branch 'main' of github.com:ampproject/amphtml
mszylkowski Mar 10, 2022
974e219
Make observable work with removing items while firing
mszylkowski Mar 17, 2022
e0a87a1
Using set for removing
mszylkowski Mar 17, 2022
5dc4e93
Remove previous code
mszylkowski Mar 17, 2022
c5d9d63
Added iterating depth
mszylkowski Mar 17, 2022
e844875
Added test to check iterations of handler removal
mszylkowski Mar 17, 2022
09809c6
Simplified impl and cleaned unused tests
mszylkowski Mar 17, 2022
be19f25
Added comment
mszylkowski Mar 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make observable work with removing items while firing
  • Loading branch information
mszylkowski committed Mar 17, 2022
commit 974e219dc69f557064b65a3b18ce414186fcdfc1
18 changes: 17 additions & 1 deletion src/core/data-structures/observable.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ export class Observable {
constructor() {
/** @type {?Array<function(TYPE=):void>} */
this.handlers_ = null;

/** @type {!Array<function(TYPE=):void>} */
this.handlersToRemove_ = [];

/** @type {boolean} */
this.iterating_ = false;
}

/**
Expand All @@ -31,13 +37,18 @@ export class Observable {

/**
* Removes the observer from this instance.
* Can be called in a handler fired.
* @param {function(TYPE=):void} handler Observer's instance.
*/
remove(handler) {
if (!this.handlers_) {
return;
}
removeItem(this.handlers_, handler);
if (this.iterating_) {
this.handlersToRemove_.push(handler);
} else {
removeItem(this.handlers_, handler);
}
}

/**
Expand All @@ -58,9 +69,14 @@ export class Observable {
if (!this.handlers_) {
return;
}
this.iterating_ = true;
for (const handler of this.handlers_) {
handler(opt_event);
}
this.iterating_ = false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this isn't capable of reentry, but it may never come up in practice. We could store a local wasIteratingBefore, and only cleanup if !wasIteratingBefore

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind explaining more? Is it that it won't work if it fires the observer again inside a fire handler?

for (const handler of this.handlersToRemove_) {
removeItem(this.handlers_, handler);
}
}

/**
Expand Down
16 changes: 16 additions & 0 deletions test/unit/core/data-structures/test-observable.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,20 @@ describes.sandboxed('data structures - Observable', {}, () => {
expect(observer1Called).to.equal(1);
expect(observer2Called).to.equal(2);
});

it('remove while firing', () => {
let observer1Called = 0;
const observer1 = () => {
observer1Called++;
};
observable.add(observer1);
const remove = observable.add(() => {
remove();
});
observable.add(observer1);

observable.fire();

expect(observer1Called).to.equal(2);
});
});