fix: dispose performance (#6894)

* fix: improve dispose performance

* chore: cleanup dispose functions

* chore: split dispose into dispose and disposeInternal

* chore: remove unnecessary node removal

* fix: remove unnecessary unbinding of event listeners

* fix: readd skipping event construction

* chore: work on fixing tests

* chore: fix remaining test failures

* chore: format

* chore: typo

* fix: first pass of PR comments

* chore: remove TODO
This commit is contained in:
Beka Westberg
2023-03-16 15:28:25 -07:00
committed by GitHub
parent c2919c51bd
commit 670f7da802
10 changed files with 82 additions and 76 deletions

View File

@@ -312,44 +312,45 @@ export class Block implements IASTNodeLocation, IDeletable {
* @suppress {checkTypes}
*/
dispose(healStack: boolean) {
if (this.isDeadOrDying()) {
return;
}
// Terminate onchange event calls.
if (this.isDeadOrDying()) return;
// Dispose of this change listener before unplugging.
// Technically not necessary due to the event firing delay.
// But future-proofing.
if (this.onchangeWrapper_) {
this.workspace.removeChangeListener(this.onchangeWrapper_);
}
this.unplug(healStack);
if (eventUtils.isEnabled()) {
// Constructing the delete event is costly. Only perform if necessary.
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_DELETE))(this));
}
eventUtils.disable();
this.workspace.removeTopBlock(this);
this.disposeInternal();
}
/**
* Disposes of this block without doing things required by the top block.
* E.g. does not fire events, unplug the block, etc.
*/
protected disposeInternal() {
if (this.isDeadOrDying()) return;
if (this.onchangeWrapper_) {
this.workspace.removeChangeListener(this.onchangeWrapper_);
}
eventUtils.disable();
try {
// This block is now at the top of the workspace.
// Remove this block from the workspace's list of top-most blocks.
this.workspace.removeTopBlock(this);
this.workspace.removeTypedBlock(this);
// Remove from block database.
this.workspace.removeBlockById(this.id);
this.disposing = true;
// First, dispose of all my children.
for (let i = this.childBlocks_.length - 1; i >= 0; i--) {
this.childBlocks_[i].dispose(false);
}
// Then dispose of myself.
// Dispose of all inputs and their fields.
for (let i = 0, input; input = this.inputList[i]; i++) {
input.dispose();
}
this.childBlocks_.forEach((c) => c.disposeInternal());
this.inputList.forEach((i) => i.dispose());
this.inputList.length = 0;
// Dispose of any remaining connections (next/previous/output).
const connections = this.getConnections_(true);
for (let i = 0, connection; connection = connections[i]; i++) {
connection.dispose();
}
this.getConnections_(true).forEach((c) => c.dispose());
} finally {
eventUtils.enable();
if (typeof this.destroy === 'function') {