7 ms·
When I need to signal something across my application, I use events: window.dispatchEvent(new Event('counterChange')); And every part of the application t
by mg 3y ago
When I need to signal something across my application, I use events:
window.dispatchEvent(new Event('counterChange'));
And every part of the application that wants to react to it can subscribe via
window.addEventListener('counterChange', () => {
... do something ...
});
Anything wrong with that?
- hk__2 3y ago> Anything wrong with that? It has all the downsides of the pub/sub architecture highlighted in the proposal.
- deleted 3y ago[deleted]
- deleted 3y ago[deleted]
- ivan_gammel 3y agoDid you read the document? They have an example there, which is quite similar to yours, and explain what is the problem.
- explaininjs 3y agoNo, they don't. In fact, if you search "event" in the proposal you get exactly one result, the prefix of "eventually". This is a serious shortcoming of the proposal that should be addressed.
- throwitaway1123 3y agoI think the comment you're replying to is referring to the pub/sub sections of the proposal. They don't explicitly mention events, but events are a subset of the publish/subscribe pattern.
- explaininjs 3y agoBut then so are signals. The only "benefit" signals as proposed here give you is less control over the exact dispatch pattern of the graph, for instance things like debouncing, throttling, batching, etc etc etc. Aka all the things you absolutely must have control over if you want to make something resembling a high performance application.
- naasking 3y agoSignals are not a subset of events. Signals combine event subscription with value construction, which promotes a remote declarative model for updates. > The only "benefit" signals as proposed here give you is less control over the exact dispatch pattern of the graph, for instance things like debouncing, throttling, batching, Events don't give you any more control over those properties than signals, they just require more boilerplate.
- ivan_gammel 3y agoOh, come on. They do have an example of architecture, not literal example of events. It doesn’t matter what trivial implementation of Observer pattern you choose.
- explaininjs 3y agoExcept one is already built into the language? And it provides all the upsides of signals with none of the downsides? (Modulo proper use of `using` directives)
- deleted 3y ago[deleted]
- deleted 3y ago[deleted]
- ahmedfromtunis 3y agoCan you please point to where in the document such an example was mentioned? I rechecked the document and couldn't find it.
- ivan_gammel 3y agoJust look for the example of a design pattern („Example - A VanillaJS Counter“ section), not for a literal implementation of it via events. Conceptually they are the same.
- djbusby 3y agoI've been using patterns like this for more than a decade. The thing that's hard is, down the road you could have a listener, which triggers a other event, then another event, which comes back to the first routine and now you got a listen-loop that won't quit. And it's hard to ensure that all listener don't cause that trigger cascade.
- zaphar 3y agoI like signals as primitive but in this particular case they make it roughly about as easy to create loops accidentally as events do. I don't think this problem gets better or worse with signals.
- naasking 3y agoSignals are a bit better because they only propagate when computed values actually changed. This is an implicit fixed point/stopping condition that doesn't intrinsically exist with events.
- eddd-ddde 3y agoIsn't it possible to define all listeners / publishers in a declarative way which can be compiled to catch for this issues?
- berkes 3y agoYes. It is. And most pub/sub or Observer architectures and design patterns have the "loop" thing solved just fine. In fact, the GOF spend an entire paragraph on the problem of complex update semantics in "design Patterns" (1995) ch Observer p299. So, while it is a real problem, it's one that has been solved (for at least 29 years)
- djbusby 3y agoYes, I want to mention, since I was up-thread, it is solved but not all tooling or environment are setup for that. When the app is small you likely don't need it. And then it grows and you absolutely do. It's better, in greenfield to use framework/tooling that is ready for it.
- cyanydeez 3y agoMostly the teardown logic and inevitable memory leaks. A alt proposal would be some kind of auto remove listener if it goes out of context
- explaininjs 3y agoThe new `using` feature handles RAII just fine. This proposal is entirely unnecessary given the existence of `using` and the already-existing event listeners. https://iliazeus.github.io/articles/js-explicit-resource-management-en/ https://iliazeus.github.io/articles/js-explicit-resource-man...
- lelandfe 3y agoQuite a good link, thanks.
- cyanydeez 3y agoNice, but mixing typescript into a proposed standard just confusing.
- explaininjs 3y agoThe standard doesn't have anything to do with TypeScript, not sure where you got that from? https://github.com/tc39/proposal-explicit-resource-management https://github.com/tc39/proposal-explicit-resource-managemen...
- cyanydeez 3y agoIm referring to the link. Trying to demonstrate a proposed feature usingvtypescript.
- gray_-_wolf 3y agoMaybe a stupid question, but isn't the memory released anyway when I close the tab? So why do memory leaks matter?
- explaininjs 3y agoThis pattern is precisely what everyone's favorite "look, JS/electron can be high performance!" example uses. (VS Code).
- zdragnar 3y agoAccording to TFA, event emitters / observables cause unnecessary work when called multiple times. The difference with signals is that the resulting value is only ever calculated when the end consumer reads the value- so you schedule render updates asynchronously from the actual writes to the signal, and whatever chain of computations the watchers perform is done just the one time during the render. Interim values sent to the signal will get lost, so you really can't do too much interesting work in them. It's really just a fancy abstraction layer to coordinate a rendering cycle.
- _the_inflator 3y agoHistorically, this example is the reason why the Web evolved into jQuery and from there forked into the world of Angular and React mainly. Event handling is getting messy very easily. If you want to get deeper into it, have a look at event bubbling and propagation. Large applications need a robust event handling. This is the nowadays hidden benefit of frameworks like Angular, Vue etc. Believe me, you don’t want to use the standard event handling API without a framework. Adding, deleting, cloning, firing, removing, fire once etc on many elements can have serious unwanted side effects.
- beezlewax 3y agoWhat kind of side effects specifically?
- doomroot 3y agoI believe memory leaks to start
- falcor84 3y agoAre you implying that there are memory leaks in browsers' internal implementation of events? Because my take is that the problem is with "user space" scripts not cleaning up after themselves, and I don't see how that would get better by adding yet another API to be mindful of.
- gibbitz 3y agoI believe this would be more related to something like memoizing a DOM structure in a "Live" listener that is later removed from the DOM but not garbage collected due to the reference in the event listener. As the poster mentioned, developer error -- not a fundamental language or browser implementation flaw.
- naasking 3y agoIf a language or browser implementation can't reclaim this unused memory thus creating a memory leak, that arguably is a flaw. It's literally a DoS attack vector that can be exploited by the untrusted scripts that run in the browser sandbox.
- nurple 3y agoWelcome to Node.js v21.6.2. Type ".help" for more information. > window.dispatchEvent(new Event('counterChange')) Uncaught ReferenceError: window is not defined
- lelanthran 3y ago> Anything wrong with that? Well, don't events only bubble upwards? You need to know the exact element of it is not on a lower level in the DOM tree. Events were too messy, so I wrote a small pub/sub message queue type of thing. Anyone anywhere in the DOM can subscribe to messages based on subject regexes. Makes things a lot easier, especially when I added web components to wrap existing elements so that publishing and subscribing is done with attributes, not js.
- everybackdoor 3y agoYou can also fire events on pretty much any object, essentially creating a channel where the message bus queue is the vm event queue.
- lelanthran 3y ago> You can also fire events on pretty much any object, Only if you have a reference to the object. The reason I made up my own message queue pub/sub is because events required a lot of complexity in acquiring the correct reference to the correct object or subtree in the DOM. With pub/sub type message queue, any element can emit a message with subject "POST /getnetpage" and the function listening for (subscribed) POST messages emits a RESPONSE message when the response comes back. This lets a third element listen (subscribe) for a "RESPONSE FROM /getnextpage" subject message, and handle it. None of the 3 parties in the above need to have a reference to each other, nor do they even have to know about each other, and I can inject some nice observability tools because I can just add a subscriber for specific message types, which makes debugging a breeze.
- fwlr 3y agoIf you mis-type ‘countenChange’ it could be quite frustrating!
- everybackdoor 3y agoIn 2024 we have linters and other static analysis tools for catching these kinds of things right in the IDE.
- berkes 3y agoIf that truly is your reason to choose or forego a software design pattern, than what the h. are you doing with JavaScript?
- dakom 3y agoIt's often desirable for UI to be described in a declarative fashion, i.e. instead of where you have "do something" (set button color to red), refactoring so it becomes "is something" (button is red if state is x) I might not be describing that well, because once you go down that road it really becomes a whole overall approach that infects the whole program (like functional reactive programming), and so it's really about how the whole flow fits together from top to bottom, and that can be very elegant. I don't think that's the right fit for everything, i.e. in gamedev it might make more sense to just update some object's position imperatively, but for UI it tends to work pretty well.
- LittleDan 3y agoLGTM! Smells like Redux (in a good way). But then ultimately at the root you probably want the event to update your “model”, and then that leads to an update of the “view”. This is the part where signals can be useful.
- Offler 3y agoLook at legend-state, it's most definitely not Redux (in a good way IMO).
- briantakita 3y ago> Anything wrong with that? It only works in browser environments.
- lelandfe 3y agoNode has EventEmitter: https://nodejs.org/en/learn/asynchronous-work/the-nodejs-event-emitter https://nodejs.org/en/learn/asynchronous-work/the-nodejs-eve... See, for instance, https://www.electronjs.org/docs/latest/api/ipc-renderer https://www.electronjs.org/docs/latest/api/ipc-renderer
- briantakita 3y agoBrowser environments don't have EventEmitter. Different event APIs between browsers & nodejs. A library (3rd party or custom) is needed to make event code isomorphic.
- kabes 3y agoSignals are also just pub/sub, but with a more ergonomic api. More ergonomic because listeners are added and released automatically. It can also be more performant, eg, say you have a computation that depends on 2 values: `result = a ? b : 0` Then if a is falsy, we don't need to recompute if b changes. This is achieved automatically with signals, but would require quite some code with classic pub/sub.
- 6510 3y agoYou have to name the function or you cant remove it :P
- unrealhoang 3y agoThe problem with events handling are, you don't actually know what needs to be done when the event trigger. Let's say you have 20 components, on counterChange, which of the 20 components need to be updated? And how? You can either do it the simple (and very inefficient), and it's React conceptually way by render all 20 of your components again with new value of counter, i.e. window.addEventListener('counterChange', () => { element.innerHTML = 20components.map(|c| c.renderHTML(newCounterValue)).join(''); }); or, you have to check the components on case by case basis on a. if the component need to be updated or not, and b. how is the most efficient way to update such component. And in TFA, if counter is changed from odd to odd, the label doesn't need to be updated. Also, multiply the number of events to the number of components can make the application go out of hand very quickly.
- mg 3y agoIf the component only wants to rerender when the counter changes from odd to even or even to odd, it can cache the value and do as it pleases.
- troupo 3y agoBut then you have to make sure that the element caches that value. With signals you don't have to do that. Your component (or parts of it) will never be re-rendered if it never uses the signal.
- febed 3y agoVery hard to debug as the application gets larger
- uzerfcwn 3y agoAs an end user, I love when web applications pass events through the DOM tree, because it allows me to easily create plugins by hooking on the same events. Youtube is a prime example of how to do things right. Unfortunately, modern frameworks really want to use their own event channels, which makes hooking a pain.