Giter VIP home page Giter VIP logo

Comments (5)

devpaul avatar devpaul commented on August 28, 2024

@drjayvee, thanks for proposing this suggestion and providing the example repo. YUI's approach feels very similar to how Flex handles bubbling and cancelable events. I had a few questions while reviewing everything I hope you would clear up.

First, I like how straight-forward it is to add bubble targets. Simply declaring bubble targets as children components are added seems natural. One thing that seems to be missing is the ability to create a capture phase in addition to bubbling due to how the map is created. Could you maybe describe how a capture phase and bubbling phase could be implemented? Also, because any object can register itself as a bubbling target I assume we will need to add cyclical checks to guard against infinite loops.

I also like the separate Dispatcher class since it enables developers to extend their own custom dispatchers. How common is it for a YUI project to extend Dispatcher to add custom behaviors? Do you think custom dispatchers could achieve the remaining functionality (i.e. cancel, stopBubbling, before, and after) if we provided hooks into certain states? My thought here is we could provide a simple Dispatcher and allow users to add their own "before all", "before", "after", and "after all" states. It may also be worthwhile investigating treating the dispatcher almost like a state machine, since this is what the conditional handling of "after" seems to accomplish, the addition of a "before" state could also allow the ability to transform, filter, or reject events.

Finally, one of my biggest concerns with events that may be canceled is it can be difficult to conceptualize what happens to events after they're canceled. In EventTarget it appears that canceled events will continue to bubble. Even if we were to prevent bubbling canceled events we would at least need to allow events to be dispatched to all sibling event handlers; otherwise handling events, and in turn object state, becomes based on the order that event handlers were added. I and many other developers saw this issue in Flex, that canceling an event didn't stop an event and if other handlers didn't check to see if the state of the event was canceled then undesired effects may happen. Flex tried to solve this by offering stopPropigation(), stopImmediatePropigation(), and priority queues, adding to the complexity. My personal feeling is if we only provide a simple Dispatcher then it is better to relegate cancelability to data, however, if we create a more complex Dispatcher with before and after hooks it would seem that we could use the before handler to filter out events in that phase.

Overall I think YUI's approach is a good starting point. Event bubbling is very promising and I'm sure we can work through the rest. I'd like to get some of these questions answered and hear your feedback to refine the approach. Thanks again 👍

from core.

drjayvee avatar drjayvee commented on August 28, 2024

@devpaul thanks for your response and questions. It's nice to see this ticket getting some attention!

Event capture

One thing that seems to be missing is the ability to create a capture phase in addition to bubbling due to how the map is created. Could you maybe describe how a capture phase and bubbling phase could be implemented?

Regarding event capturing, the short answer is that YUI's EventTarget doesn't support it, so I haven't implemented it. 😄

In general, Javascript developers are used to bubbling because that's the DOM's default method. Capturing is available, however, and it makes sense for a library to offer both alternatives, I guess.

If dojo followed the DOM (and event listeners are registered for either bubbling or capturing), then capture support can always be added later, since that won't break the bubbling-only API. Therefore, I would propose to implement bubbling-only now and add capture later (if desired).

One thing to reconsider is the name of the addBubbleTarget method. If "bubble" targets can also capture events, maybe the name should change to make that clear.

Also, because any object can register itself as a bubbling target I assume we will need to add cyclical checks to guard against infinite loops.

I hadn't thought of that. I agree that infinite loops must be prevented.

Custom Dispatch

I really only wrote a separate Dispatch class to make the code readable, not because I intended for custom implementations to be used. I have no idea whether that happens in YUI3 implementations (I know only one...), or whether it's even possible. Therefore, I haven't considered the alternatives and features that you mention.

The Dispatch class in the current implementation doesn't know what bubble targets are present, so a custom implementation can't simply implement capture by changing the dispatch method. Some refactoring is required to enable more complicated event flows.

I guess the logic in EventTarget._fireEvent could be moved to Dispatch to enable some customization of the event flow.

Alternatively, EventTarget could construct a graph of targets (and detect loops in the process!) and walk the graph in _fireEvent to implement different ordering of targets for capture / bubbling.

Event cancelling

In EventTarget it appears that canceled events will continue to bubble.

I have to admit I haven't thought about the state machine too well, and have implemented it differently from YUI3.

You're right that canceled events continue to bubble. They also are delivered to other subscribers! In my implementation, Event.cancel() has the same effect as Event.preventDefault() in YUI3. Maybe the name cancel isn't well chosen here.

YUI3's EventTarget offers stopPropagation and stopImmediatePropagation methods, which change the flow of an event.

I haven't thought in depth about what would be both an intuitive and powerful feature set here, and have not implemented any features that change the flow of events. (The only feature in my implementation is that after subscribers are not called if an Event has been cancelled.)

I and many other developers saw this issue in Flex, that canceling an event didn't stop an event and if other handlers didn't check to see if the state of the event was canceled then undesired effects may happen.

Here's where after subscriptions are extremely useful! These only get notified if an event has not been cancelled in the on (or before) phase. Events in the after phase are not cancelable.

Therefore, users should generally subscribe after to prevent exactly the problem you're describing. You only subscribe on on if you need the ability to cancel events, which is the exception, not the rule. YUI puts it this way:

Use after() to subscribe to events with a default behavior when you want to react to the event with a side effect. Use on() to subscribe to events if you need to prevent or alter the default behavior or if they don't have default behavior.

Conclusion

I've used YUI3's EventTarget (and AttributeObservable) a lot (but only on one project), and love how expressive and powerful, yet simple and intuitive code using these APIs is. What I've implemented is mostly the feature (sub)set I use(d). I do appreciate that YUI3's design might not provide enough flexibility for some.

The challenge is to select a feature set that is powerful enough to enable different patterns, yet simple enough to learn and mentally reason about. (Priority queues for event subscriptions sounds awfully complicated in that regard IMHO.)

Since I'm only familiar with YUI and have no experience designing libraries for other users, I'm not sure I can be of much help.

from core.

mwistrand avatar mwistrand commented on August 28, 2024

There have been a number of times in the past that I have wished dojo/Evented could do a little bit more, so it's nice to see these efforts.

Following on the heels of the previous comments, a capturing phase could be implemented similarly to how dojo-core/aspect separates "before" and "after" advice (and with a syntax not unlike that of EventTarget.addEventListener. The on method could have a useCapture: boolean = false argument that, when true, adds the callback to a separate registry to be executed before the bubble listeners. Each of those listeners would also have the ability to stop the event from propagating (in which case, CustomEvent#stopBubbling could be renamed CustomEvent#stopPropagation).

The main difficulty is efficient execution, since either the event would first have to bubble up before executing in order to determine the top-level object, or some sort of caching mechanism would need to be used to store an object tree.

That said, I am still trying to wrap my mind around how all of this would fit in with/affect the the ideas being formulated about what a Dojo 2 application will look like. The idea is that individual components (whether that be a widget or some other object) would create cancelable actions, which then would update a store that reports back to components listening for updates. This emphasis on single-direction data flow differs from how a lot of applications were/are built with Dojo 1. With this in mind, do you have any ideas on how this additional event system might be used to improve this unidirectional data flow?

I sincerely hope this question does not come across as dismissive, especially since I can think of a few projects where something exactly like what is being proposed here could have solved certain unpleasant problems. However, since the target audience for Dojo 2 is teams developing large, enterprise applications, providing them with tools that allow them to depart from decided-upon conventions could be confusing.

from core.

drjayvee avatar drjayvee commented on August 28, 2024

I'm not sure that capturing makes that much sense, actually. It works well in the DOM because parentNodes are their childrens' bubble target by default. That means that pretty much every event can be captured by the topmost node.

I doubt there will be node chains / trees in an application, unless the framework makes that the default structure.

I really can't comment on what would work for Dojo 2 applications. I've never written an enterprise-level application, nor have I ever used Dojo 1.

I do have a nice example of the usefulness of YUI's EventTarget API: radio button groups.
First consider ToggleButton, which has a pressed state, and updates its DOM node after('pressedChange').

The ButtonGroup has ToggleButton children. The group subscribes using on('pressedChange') so it can cancel "unpress" changes (in a radio group, you cannot unpress the pressed button).

This is a nice example of the on / after subscription model with cancelable events.

When a button is added to the group, the group adds itself as that button's bubble target, so bubbling is used as well. (This is mostly for convenience: the group could subscribe to buttons individually, of course).

Obviously, this model isn't just for tiny systems like button groups. But whether it works as the basis for an enterprise-level application framework I really don't know.

from core.

kitsonk avatar kitsonk commented on August 28, 2024

This is a long running topic. I don't think it is closed and it is related directly to dojo/compose#67.

I am going to close for now and I think we should focus on making dojo/compose#67 a success. If that causes features/changes in dojo-core great, but we should track those as new issues.

from core.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.