Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

focused:from bindings on can-slot cause DOM focus method to be called, causing layout thrashing #5511

Open
1 of 5 tasks
rjgotten opened this issue Nov 3, 2020 · 5 comments · May be fixed by canjs/can-stache-bindings#558

Comments

@rjgotten
Copy link

rjgotten commented Nov 3, 2020

How often can you reproduce it?

  • Always
  • Sometimes
  • Rarely
  • Unable
  • I didn’t try

Description:

Steps to reproduce:

  1. Create a Component which passes values through a can-slot binding focused:from="anyViewModelProperty"
  2. Change the anyViewModelProperty
  3. The focused behavior from can-attribute-observable/behaviors runs and tries to execute the DOM focus method on the <can-slot> element.
  4. Observe in Chrome's profiling tools that this causes a forced reflow and layout thrashing.

Expected results:

Special behaviors such as focused are not applied to can-slot and this problem is not triggered.

Actual results:

Special behaviors are applied and this problem is triggered, causing performance degredation during large view updates.

Environment:

Software Version
can version 5.33.2
Browser Any
Operating system Any
@rjgotten
Copy link
Author

rjgotten commented Nov 3, 2020

I'm currently hot-patching my local copy of can-attribute-observable to work around this, by simply disabling all special behaviors on can-slot elements by explicitly for their tag name.

It makes zero sense to process them for slots anyway, as they're elements that are never actually present in the real DOM tree and are just kept around in memory to pass along bindings, afaict. Bindings that should work like view model bindings, and not element bindings.

As far as other workarounds go: attempting to explicitly use vm:* bindings on a slot triggers a dev warning that it doesn't have an associated view model, so that one also doesn't work.

Wonder if it's possible to update can-stache-bindings to NOT use AttributeObservable for slots...

@rjgotten
Copy link
Author

rjgotten commented Nov 3, 2020

Can confirm that modifying the attribute type binding in can-stache-bindings to return a SimpleObservable for can-slot nodes instead of an AttributeObservable works:

// ### getObservableFrom.attribute
// Returns a compute that is two-way bound to an attribute or property on the element.
attribute: function(bindingData, bindingContext ) {
  if(bindingData.name === "this") {
    return canReflect.assignSymbols({}, {
      "can.getValue": function() {
        return bindingContext.element;
      },

      "can.valueHasDependencies": function() {
        return false;
      },
      "can.getName": function getName() {
        //!steal-remove-start
        return "<"+bindingContext.element.nodeName+">";
        //!steal-remove-end
      }
    });
  } else if (bindingContext.element.nodeName.toLowerCase() === "can-slot") {
    return new SimpleObservable(undefined);
  } else {
    return new AttributeObservable(bindingContext.element, bindingData.name, {}, bindingData.event);
  }

}

Also feels considerably faster to go through the initial UI build-up in my application which uses lots of slot-based composition.
Not that strange really, considering how much unneeded weight AttributeObervable adds over SimpleObservable.


[EDIT]

Profiled it with Chrome and it indeed shaves ~100ms off.

@justinbmeyer
Copy link
Contributor

Thanks for reporting!

@cherifGsoul
Copy link
Member

Hey @rjgotten , what do you want to achieve with this binding if the property will be removed?

@rjgotten
Copy link
Author

@cherifGsoul

I'm passing a focused property through the can-slot to the implementing can-template element. It's a template slot for rendering one item of the list in a rich dropdown selection widget. The focused property is used to track whether the item is the list's item under focus, so that an item can-template implementation can adapt to that changed state.

Just using the name focused triggers the DOM focus behavior and causes a lot of thrashing.
And it makes no sense, because a can-slot or can-template element is never present in the living DOM, so there is never anything to focus -- or to apply any other binding logic to, for that matter. Bindings on slots are purely a pass-through to the implementing templates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants