esl icon indicating copy to clipboard operation
esl copied to clipboard

[🚀 esl-core]: ability to share debounced resize across ESLEventListeners

Open ala-n opened this issue 1 year ago • 1 comments

As an ESL consumer, I want to be sure that subscriptions to the frequently dispatched event can be optimized at the library level.

Use case:

class MyEl {

   @listen({event: 'resize', target: window})
   @decorate(debounce, 200)
   onResize() {
   }
}

Frequent env events (like 'resize') are usually globally optimized by decorating it using debounce or throttle.

Current behavior: Each instance of MyEl and other similar components subscribes to the window.resize globally and decorates the result callback locally for each instance.

Proposed behavior: Ability to make a shared denounced target for window.resize and throttled for window.scroll

ala-n avatar Sep 02 '22 10:09 ala-n

Draft solution: make the user able to define custom handlers (hooks)

TODO: POC @ala-n to create a story for POC variation

Pros:

  • ... Cons:
  • complications of listener

ala-n avatar Oct 11 '22 11:10 ala-n

Rust to renew cases are:

  • window resize event denounced version (main use case with a shared equal debounce)
  • window scroll event throttled version (main use case with a shared equal timeout) Note: that's only cases we faced, but that doesn't mean that we do not need denounced scroll, or no need to have a customizable timeout. Here is a list of API drafts to think:
  @listen({
    // But how to pass the timeout...
    event: 'resize:debounced resize:throttled',
    // Lazy getter for WindowEventProxy
    target: ESLEventUtils.window
  })
@listen({
   event: 'resize',
   target: ESLEventUtils.debounced(300)(window)
 })
 @listen({
   event: 'resize',
   target: ESLEventUtils.throttled(300)(window)
 })
@listen({
    event: 'resize',
    // Resize observer case
    target: (that) => ESLEventUtils.resize(that.$el)
  })
  @listen({
    event: 'resize',
    // Resize observer case
    target: (that) => ESLResizeObserverTarget.create(that.$el)
  })
@listen({
    event: 'enter leave intersect',
    // Hold all utility event targets under ESLEventUtils
    target: ESLEventUtils.viewport
  })
  @listen({
    event: 'enter',
    // If we need another target thaen current element
    target: (that: MyComponent) => ESLEventUtils.viewport(that.$el)
  })
  @listen({
    event: 'leave',
    // Have a separate class for event targets
    target: ESLEventHelpers.viewport
  })
@listen({
    event: 'enter',
    // Or mb we don't need a "cumulative" class at all ...
    target: ESLIntersectionTarget.instance
  })
  // Window proxy variations (not clear how to deal with element resize)
  @listen({
    event: 'resize',
    target: ESLWindowProxy.resize.debounce(300)
  })
  @listen({
    event: 'scroll',
    target: ESLWindowProxy.scroll.throttle(300)
  })

We can use them as a basis and chose a good to define the common pricipals

ala-n avatar Feb 08 '23 15:02 ala-n

  1. 2 impl +1 vote from API point of view (??? )
  2. +1 vote against event aliases
  3. +1 vote for a totally separate impl for Intersection and ResizeObserv
  4. +8.5
  @listen({
    event: 'resize scroll',
    target: ESLEventUtils.window.debounced
  })
    @listen({
    event: 'resize scroll',
    target: ESLEventUtils.window.throttled
  })
  @listen({
    event: 'enter',
    target: ESLEventUtils.intersection
  })
  @listen({
    event: 'resize',
    // How to handle edge cases
    target: ESLEventUtils.resize
  })
  1. +7.6 ESLEventUtils as an API holder -1.5
  2. +8.6 Do not care about super custom cases

ala-n avatar Feb 10 '23 12:02 ala-n