Skip to content

Improve performance of quick bar#7359

Merged
bramkragten merged 12 commits intodevfrom
quick-bar-speed
Oct 21, 2020
Merged

Improve performance of quick bar#7359
bramkragten merged 12 commits intodevfrom
quick-bar-speed

Conversation

@bramkragten
Copy link
Member

Proposed change

I noticed the quick bar could be pretty sluggish, added virtualization and some more improvements for speed (and some style).

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (thank you!)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Example configuration

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:

Checklist

  • The code change is tested and works locally.
  • There is no commented out code in this PR.
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

@donkawechico
Copy link
Contributor

I pulled this branch and tried locally with demo: enabled and I gotta be honest... This feels noticeably more sluggish to me :-\

I haven't examined the code yet, so I'll look at that and maybe put in some sort of timing mechanism

@donkawechico
Copy link
Contributor

donkawechico commented Oct 16, 2020

Here's what I'm talking about. Using devtools performance tab:

quick-bar-speed (3 paints / ~150ms)

dev branch (1 paint / ~55ms)

The same thing happens if I hit backspace and type the "h" again (testing caching).

Can you try the chrome perf tool locally and verify what I'm seeing?

@donkawechico donkawechico self-assigned this Oct 17, 2020
@donkawechico
Copy link
Contributor

Is it just me or does it now look like it has too much top padding? (I know it's the same padding, but maybe the icon is widening the gap between field and top?

Copy link
Contributor

@donkawechico donkawechico left a comment

Choose a reason for hiding this comment

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

As I was studying the code I realized a lot of this is going to change with the refactor PR. I think it would make more sense to review this once we merge the two and see how it all shakes out.

this._commandTriggered = -1;
this._commandItems = undefined;
this._entities = undefined;
this._filteredItems = undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is possible (see further down), but it occurred to me there could be a perf opportunity here:

The idea being: remove these undefined assignments, change showDialog() to reuse existing list, then change updated to invalidate the cache if it notices a New, Removed, or Renamed entity.

So like:

public async showDialog(params: QuickBarParams) {
//...
  this._entities = this._entities || Object.keys(this.hass.states).map<HassEntity>(
      (entity_id) => this.hass.states[entity_id]
  );
//...

public updated(changedProperties) {
  if (
      changedProperties.has(_propertyThatIndicatesANewEntity) || 
      changedProperties.has(_propertyThatIndicatesARemovedEntity) || 
      changedProperties.has(_propertyThatIndicatesARenamedEntity
    ) { 
      this._entities = undefined;
  }
}

The reason I doubt this is feasible is that I'm not sure there's a simple property that indicates whether something was added... I think it's just a big list of existing states?

this._itemFilter = "";
this._filter = "";
this._commandTriggered = -1;
this._commandItems = undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor:

We could probably remove this line and let the command list stay cached for next launch since the command list will very rarely change in the middle of a session.

Comment on lines +28 to +34
import memoizeOne from "memoize-one";
import "../../common/search/search-input";
import { mdiConsoleLine } from "@mdi/js";
import { scroll } from "lit-virtualizer";
import { styleMap } from "lit-html/directives/style-map";
Copy link
Contributor

Choose a reason for hiding this comment

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

I see you stopped using the VScode auto organize imports 😜

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep 😄

Comment on lines +183 to +187
private _handleSelected(ev: SingleSelectedEvent) {
const index = ev.detail.index;
const item = (ev.target as any).items[index].item;
this.processItemAndCloseDialog(item, index);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the purpose of this function just to separate the concept of "handling a selection" and "how to execute quick bar commands"?

Copy link
Member Author

Choose a reason for hiding this comment

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

it is to get the index and items from the event detail

Copy link
Contributor

Choose a reason for hiding this comment

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

But that was already being done inside processItemAndCloseDialog. Seems like an unnecessary abstraction to me.

Copy link
Contributor

@donkawechico donkawechico left a comment

Choose a reason for hiding this comment

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

I just found a bug where command items aren't executing even if you click. Styling is off too.

@bramkragten bramkragten merged commit 54ec379 into dev Oct 21, 2020
@bramkragten bramkragten deleted the quick-bar-speed branch October 21, 2020 11:07
@bramkragten bramkragten mentioned this pull request Oct 21, 2020

ha-icon {
color: var(--secondary-text-color);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@bramkragten Why is this ha-icon styling no longer in dev?

Current dev:

@media (min-width: 800px) {
ha-dialog {
--mdc-dialog-max-width: 800px;
--mdc-dialog-min-width: 500px;
--dialog-surface-position: fixed;
--dialog-surface-top: 40px;
--mdc-dialog-max-height: calc(100% - 72px);
}
}
ha-svg-icon.prefix {
margin: 8px;
}
.uni-virtualizer-host {
display: block;
position: relative;
contain: strict;
overflow: auto;
height: 100%;
}

I looked through git blame and the commit history of ha-quick-bar and I don't see anything that removed it O_o

Copy link
Contributor

Choose a reason for hiding this comment

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

It probably doesn't matter, icons look okay in dark mode.

But it does seem spooky that this code could vanish without a github trace.

Copy link
Member Author

Choose a reason for hiding this comment

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

I made a general PR to make it general

: fuzzySequentialMatch(filter, item.text);
return item;
})
.filter((item) => item.score === undefined || item.score > 0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this in here? This would return all invalid items.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fixed here: #7430

Copy link
Member Author

Choose a reason for hiding this comment

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

That's your code 😅

Copy link
Contributor

Choose a reason for hiding this comment

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

lol, it is? 😆 Man I need to learn to read git history better. Sigh...

value=${this._commandMode ? `>${this._itemFilter}` : this._itemFilter}
.filter=${this._commandMode ? `>${this._filter}` : this._filter}
@keydown=${this._handleInputKeyDown}
@focus=${this._resetActivatedIndex}
Copy link
Contributor

@donkawechico donkawechico Oct 22, 2020

Choose a reason for hiding this comment

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

Why was all the activated index stuff (styling the topmost and highlighted row) removed in a PR about perf? And without a review?

To me, that was a pretty helpful visual styling and would've liked to discuss in review context.

Copy link
Member Author

@bramkragten bramkragten Oct 22, 2020

Choose a reason for hiding this comment

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

Because it didn't work anymore. Also it was using the wrong methods. If we would want to make the focus color different, we should change the css for that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough!

Comment on lines +192 to +197
${this._commandTriggered === index
? html`<ha-circular-progress
size="small"
active
slot="meta"
></ha-circular-progress>`
Copy link
Contributor

Choose a reason for hiding this comment

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

Moving the circular progress bar inside this async renderItem breaks the progress bar. We never go back into this function after this._commandTriggered gets a value so the progress bar never appears.

@github-actions github-actions bot locked and limited conversation to collaborators Jul 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants