15 ms·
A proposal to add signals to JavaScript
- dclowd9901 2y agoCool. My least favorite, cumbersome and brittle aspect of using Ember becoming a core aspect of JavaScript functionality. No fucking thank you.
- artemonster 2y agoEasier to port react to vhdl or verilog?
- nullvoxpopuli 2y agoSocials: - Reddit: https://www.reddit.com/r/javascript/comments/1bsgnf5/tc39_proposal_for_signals_reactive_primitives_is/ https://www.reddit.com/r/javascript/comments/1bsgnf5/tc39_pr... - X/Twitter: https://twitter.com/nullvoxpopuli/status/1774496900915327100 https://twitter.com/nullvoxpopuli/status/1774496900915327100 - Masto: https://mastodon.coffee/@nullvoxpopuli/112191605019758002 https://mastodon.coffee/@nullvoxpopuli/112191605019758002 - Blue Sky: https://bsky.app/profile/nullvoxpopuli.bsky.social/post/3koz4npobok2o https://bsky.app/profile/nullvoxpopuli.bsky.social/post/3koz...
- senoralligator 2y agoSurely it would be better to fix the interoperability issues of the language? "Lets just add a single implementation of everything to the standard!" seems like quite a strange response to "users of the language are having trouble with interoperability due to false coupling."
- polynomial 2y agoIsn't this similar to small core vs large core debates you see in other projects, often where drivers are concerned? (ie question around where the coupling layer is materialized)
- jauntywundrkind 2y agoI don't think the language hurts or hinders interop much? It has a wide range of tools that can adapt objects between different shapes, for when we do have two similar but different interfaces we are trying to bridge. I struggle to see what more one could want. Do you have any specific features you think would help a massive ecosystem of packages be able to work together, when for example different packages have different Signal implementations?
- senoralligator 2y agoBetter ways to describe polymorphism, a better type system in general really. Look to async Rust for a great example of such interoperability.
- nullvoxpopuli 2y agois it strange? Vue reactivity isn't compatible with Svelte, nor Angular. As a counter example to your question, what if we all had competing implementations of the object primitive. Libraries would barely work with one another and would need an interop layer between them (just as reactivity layers do today!)
- senoralligator 2y agoI'll admit I don't use JavaScript very often, but surely the state of polymorphism could be improved? For example, C++ recently added concepts, and most (modern) languages have some way to describe interfaces. As to your counterexample, I agree with current JavaScript that would be a problem, but with good language support it would certainly be possible. For example, Rust (and C++?) have competing implementations of the global allocator, and must users will never notice.
- zdragnar 2y agoThe reactivity layers are all pretty tied into the hearts of the frameworks. There's no advantage to any framework to expose such a thing to end users to leverage a competing implementation. As for polymorphism, even the current class syntax largely operates in the same way as the original prototypal inheritance mechanism, with a few exceptions in constructor behavior to support subclassing certain built-in objects. You can pretty easily create run-time traits- like functions with prototpyes, the class construct is an expression whose resulting value can be passed around, mutated, etc. For example, you can write a function that takes a class as an argument, and returns a new class that extends it.
- __s 2y agoPromises are a nice success story, but without async/await it wasn't really necessary to standardize > The current draft is based on design input from the authors/maintainers of Angular, Bubble, Ember, FAST, MobX, Preact, Qwik, RxJS, Solid, Starbeam, Svelte, Vue, Wiz, and more… Would be interested what existing library authors think of this proposal. Interesting that React is not in that list Signals are a bit like channels, except they're broadcast instead of single receiver. It'd be neat if this could somehow be leveraged to allow web workers to communicate with channels instead of onMessage callbacks. Specifically being able to `select` over signals/channels/promises like in Go would over a syntactic benefit over having to try manage multiple concurrent messaging mechanism with callbacks (maybe by allowing signals to be included in `Promise.any`)
- watson 2y ago> Promises are a nice success story, but without async/await it wasn't really necessary to standardize One benefit of standardisation that's not tied to async/await is that the JavaScript engines has been able to do performance optimisations not otherwise possible which benefit Promise-heavy applications
- KRAKRISMOTT 2y agoMaybe they can call it "EventEmitter" https://nodejs.org/en/learn/asynchronous-work/the-nodejs-event-emitter https://nodejs.org/en/learn/asynchronous-work/the-nodejs-eve...
- __s 2y agoThat looks like it fits with the theme, but events are difficult to compose & tend to have easy leaks by requiring explicit attach/detach (not that I'm sure the proposal here addresses those issues)
- pcthrowaway 2y agoCould you not just compose a new EventEmitter constructor that uses the new FinalizationRegistry API to drop all handlers of subjects which have since been garbage collected?
- lambdaba 2y agoThis looks very much like mobx, which is my favorite JS effect system. Here is the mobx version: import { observable, computed, autorun } from 'mobx'; const counter = observable.box(0); const isEven = computed(() => (counter.get() & 1) === 0); const parity = computed(() => isEven.get() ? "even" : "odd"); autorun(() => { element.innerText = parity.get(); }); // Simulate external updates to counter... setInterval(() => counter.set(counter.get() + 1), 1000);
- kabes 2y agoWell, mobx is signals. But signals where the dependencies are tracked implicitly via the proxy ovject, instead of explicitly by a getter.
- alserio 2y agoreally looking forward to get nice dev tools out of this work
- ivanjermakov 2y agoIs dependency tracking problem statically solvable (without calling effect once and subscribing to all .get's)? I don't think this needs to be a language feature, rather abstraction of existing features. In other words, can't this be a library? I know that SolidJS is able to figure out dependent signals, but probably doing so on the first execution.
- ivan_gammel 2y ago>In other words, can't this be a library? It is explicitly mentioned in the proposal. The problem with 3rd party libraries is their interoperability and diversity of implementations, which might be unnecessary for this kind of things.
- twiss 2y agoI believe Svelte does figure it out at build time. Which does make me question the mention of Svelte in the proposal, and makes me wonder what the Svelte developers think of it - because IIUC they indeed don't need this (at runtime), if I'm not mistaken.
- Phillippe 2y agoThe current Svelte version does it at build/compile time. The up and coming Svelte 5 is using signals and the reactivity is moved to runtime
- bastawhiz 2y ago> In other words, can't this be a library? You answered your own question: > I know that SolidJS is able to It already is, obviously. But how is SolidJS supposed to work with other non-SolidJS code? It can't. Unless every library builds support for every other library, they can't possibly interoperate.
- ivanjermakov 2y agoIt's a shame that JS ecosystem is so sparse. E.g. in Rust it's much more common to rely on existing "building blocks" like futures, tokio, syn, serde even just for basic bindings, favoring interoperability.
- mg 2y agoWhen 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?
- fwlr 2y agoIf you mis-type ‘countenChange’ it could be quite frustrating!
- everybackdoor 2y agoIn 2024 we have linters and other static analysis tools for catching these kinds of things right in the IDE.
- berkes 2y agoIf that truly is your reason to choose or forego a software design pattern, than what the h. are you doing with JavaScript?
- ivan_gammel 2y agoDid you read the document? They have an example there, which is quite similar to yours, and explain what is the problem.
- explaininjs 2y 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 2y 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.
- lloydatkinson 2y agoSorry but I’ll be a little bit mad if this Preact/Angular inspired thing is approved and made part of the spec, while Observable was deliberately ostracised.
- troupo 2y ago> I’ll be a little bit mad if this Preact/Angular inspired thing Signals predate both and originate in KnockoutJS at least. They were popularized in recent years by SolidJS. And then adopted into Preact, Vue and others. Angular is a very late newcomer to the signals game. Edit: and this is literally in the introduction section: --- start quote --- This first-class reactive value approach seems to have made its first popular appearance in open-source JavaScript web frameworks with Knockout in 2010. In the years since, many variations and implementations have been created. Within the last 3-4 years, the Signal primitive and related approaches have gained further traction, with nearly every modern JavaScript library or framework having something similar, under one name or another. --- end quote --- The list of libraries in the README is alphabetized, and doesn't reflect the evolution of signals in the frameworks and libraries.
- Cloudef 2y agoSignals are actually much older concept from 70s introduced in smalltalk as a ValueHolder. Later Qt reused the same concept and called them "signals & slots".
- ivan_gammel 2y agoI like the quality of this proposal, which reminds me of JSRs. It does make a lot of sense.
- andrewstuart 2y agoWhat does this buy me over events?
- troupo 2y agoAutomatic dependency tracking, guarantees against circular references, improved observability and potentially better devtools
- andrewstuart 2y agoThat’s not enough to compete with an existing “good enough” solution.
- troupo 2y agoThere's no existing "good enough" solution for reactive values in JS. Also https://news.ycombinator.com/item?id=39887187 https://news.ycombinator.com/item?id=39887187
- claytongulick 2y agoGetters and setters work pretty well. addEventListener("foo", () => {...}, {once: true}) Is a pretty easy way of handling one-shot events. Those have been "good enough" for me to build large, complex healthcare applications.
- andrewstuart 2y ago>> Getters and setters work pretty well. What do you mean can you explain more?
- claytongulick 2y agoSure. I structure my apps with light DOM vanilla web components, using lit-html (not lit) as a renderer. I'll use a hypothetical patient profile component as an example. Let's say that it's a top level "page" and needs to support deep linking. set patient_id(value) would trigger a loadPatient(). loadPatient would set this.patient when loading is complete. The setter for this.patient triggers a render and paints the component. You can expand on that as needed. Maybe sometimes I want to render that component in a modal, maybe sometimes as a slide out drawer. Maybe there are little differences in the header or something depending on how it's being hosted - I can just add a setter for something like "display_mode" (making this up) that would trigger a render on change. It's really no different than any reactive flow, and about the same as big frameworks when you count total LOC, but it's all just vanilla and simple. For cross component communication, custom events work great, especially the one-shot ones. In a component constructor, I can add a listener, assign a property or call a component function, and the reactive flow just goes as normal. No framework needed. Works with any renderer, if you don't like lit-html, there are JSX and others out there. I like lit-html because it's super fast template node clones, so you don't need to worry about calling render() redundantly, it's cheap.
- makkesk8 2y agoLooks useful, but what baffles me is.. Why is every framework setting state or their "signals" using "setX" functions? What's wrong with the built in getter and setters that you can either proxy or straight up override? This feels arguably cleaner: something = "else"; Than: setSomething("else");
- j1elo 2y agoFor one I can write ".set" and the IDE would auto-complete with all possible somethings that can be set, even without having the slightest idea of which ones there are. I've very much enjoyed this kind of consistency wherever is found (having a common prefix for common behaviors, in this case, setters)
- dclowd9901 2y agoOne big problem is right now they are _tremendously_ slow to use. (At least through the Proxy native class). Not sure if this is an artifact of JITs or the nature of prototypal inheritance.
- notnullorvoid 2y agoSome libraries that feature signals style reactivity do use getter and setters (ember.js, and mobx are 2 good examples). However it makes sense for the primitive API to use functions since getter and setters are functions under the hood and get applied to an object as part of a property descriptor. It's also not always desirable to have a reactive value embedded in an object, sometimes you just want to pass around a single changeable value. As for why some libraries choose the `[thing, setThing] = signal()` API (like solid.js) that's often referred to as read write segregation. Which essentially encourages the practice of passing read only values by default, and opting in to allowing consumer writes on a value by explicitly passing it's setter function. This is something that was popularized by React hooks. Either way this proposal isn't limiting the API choice of libraries since you can create whatever kind of wrappers around the primitive that you want.
- chuckadams 2y agowell to use setters it has to be "foo.something = else", because JS can't override plain old local bindings -- not since "with" was sent to the cornfield anyway. Once you do that, you can indeed have a framework that generates getters and setters, which is exactly what Vue 2 does. Switch to proxies instead of get/set and you have Vue 3 -- the signals API is pretty much identical to the Vue composition API.
- everybackdoor 2y ago- They’re saying ”the community wants less boilerplate” - They introduce what is effectively a black-box system - The new system is expected to handle all application state - They try to push it for frontend folks while also remarking that it would be useful for build systems This has the same red flags the xz saga had. Have we learnt nothing. Lots of ”users” here vouching for the pattern and hoping it gets adopted. I bet this gets some nice damage control replies because there’s social engineering going on here right now and most seem to not be aware of it.
- londons_explore 2y agoCan't we just call javascript 'done'? We keep adding things to the language, and never subtract anything, which means learning it as a language is getting harder and harder.
- Waterluvian 2y agoI dunno. I sometimes feel the same, but a whole ton of recent features have been incredible at cleaning up code. ?? Is my favourite. I also want set functions and possibly a match statement thingy.
- troupo 2y agoThey don't add these to the language. They add these to the (currently basically non-existent) standard library. Given that almost every single framework under the sun (except React) has converged on signals, it makes sense to move that into the browser. This... this is how the web is supposed to work.
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- recursive 2y agoYou may hereby consider `with` to be removed. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- angleofrepose 2y agoOff topic, but I’m wondering if anyone attracted to this topic could help me understand why JavaScript doesn’t have macros. I’m aware of much conversation around dismissing macros, often in the context of bad dev experience — but this sounds like a shallow dismissal to me. At the end of the day, we have some of the results of macros in the JavaScript ecosystem, but rather than being supported by the language they are kicked out to transpilers and compilers. Can anyone point me to authoritative sources discussing macros in JavaScript? I have a hard time finding deep and earnest discussion around macros by searching myself.
- hoten 2y agoYou could start here: https://github.com/search?q=org%3Atc39%20macro&type=code https://github.com/search?q=org%3Atc39%20macro&type=code
- angleofrepose 2y agoA great resource that I should have found on my own. Thank you. I’ll look through this later. Giving it a quick glance now I see some of the same language I see other places; here that macros are “too far.” I don’t know why macros are approached with apprehension. As I briefly get at in my first comment, I’m aware of a lot of dismissals of macros as a tool, but those dismissals don’t make sense to me in context. I’m missing some backstory or critical mind-share tipping points in the history of the concept. What could be a good set of sources to understand the background perspective with which TC39 members approach the concept of macros?
- notnullorvoid 2y agoMacros don't really make sense in JS runtime spec. Since you can mostly already achieve macro level features by using eval or new Function, but it's not very efficient. Macros make most sense at build time, and there have been a few attempts at generalized build macros with various bundlers / transpiler plugins. I think the space needs more time to mature. I'm optimistic that we'll eventually see some sort of (un)official macro spec emerge.
- bastawhiz 2y ago
- calebpeterson 2y agoNot a bad thing at all… but this is the same mental model provided by the so-called atom-based state management systems in React. I believe Jotai is the most popular.
- kookamamie 2y agoLooks bad. It adds what looks like more nonsense complexity. Also, "Signals" as a name is not descriptive to what is proposed (see e.g. Qt Signals).
- tqwhite 2y agoYes. Thank you. I am already tired trying to figure out how this would improve my life and annoyed at trying to read other people's code that has more abstracted crap in it.
- cuddlecake 2y agoPromises are, technically speaking, "abstracted crap". So is abstracted crap only ok if it's already in the JS standard library?
- Izkata 2y agoPromises proved themselves in libraries before they got added to Javascript.
- troupo 2y agoSignals have, too. And it is literally spelled out in the readme, in the introduction section
- Izkata 2y agoThey did create a polyfill, but the readme says it was based on design input from other projects, not on aligning multiple existing designs. This at least sounds like the opposite of what happened with promises, where they already existed in multiple libraries before the Promises/A design came out.
- troupo 2y ago> where they already existed in multiple libraries Signals exist in multiple libraries with what are really minor variations on the theme. > before the Promises/A design came out. That's why the current proposal asks for input about design. IIRC, promises also had multiple iterations on the design. There were calls to make them more monadic, less monadic, cancelable, non-cancelable etc. And the original proposal looks nothing like the eventual API: https://groups.google.com/g/commonjs/c/6T9z75fohDk https://groups.google.com/g/commonjs/c/6T9z75fohDk [1] And new things are still being added to them (like Promise.withResolvers etc.) [1] There's a great long presentation on the history of promises here: https://samsaccone.com/posts/history-of-promises.html https://samsaccone.com/posts/history-of-promises.html
- rblatz 2y agoThe lack of signals isn’t remotely the largest issue with JS, and adding them has minimal impact for most users of JavaScript. The biggest issue is the lack of a standard library, resulting in npm hell in most projects.
- phpnode 2y agoJS does have a standard library and this proposal is about expanding it, so that’s good, right?
- mrpepka 2y agoUnless it's half-assed, clumsy and short-sighted, and we are stuck with it forever, because standard. Until one's implementation becomes a standard thanks to the fact it wins as a library (as jQuery did), it should not be slyly forced into the language.
- alexchamberlain 2y agoThis is referenced in the proposal: > JavaScript has had a fairly minimal standard library, but a trend in TC39 has been to make JS more of a "batteries-included" language, with a high-quality, built-in set of functionality available I think the description "minimal" is fairer than "no" wrt the standard library.
- preommr 2y agoStrongly disagree - it's trivial for a project to just add a small std-lib, or add lodash as a single dep, or just add it directly as source code. JS projects exist in npm hell because people have been taught to use a library to save typing 10 characters. No standard library is going to fix. Because someone can just call in a new lib that just curries something in the standard lib with minor improvements like caching.
- qudat 2y agoIt's getting better. I can build a medium-sized, modern TS/React app with 12 dependencies. A large enterprise app will be closer to 30-40 which is still a marked improvement over previous dep lists.
- tambourine_man 2y agoI’ve been trying for decades to understand why people find it so hard to keep track of state and update the DOM. Sure, it requires a bit of discipline, but it’s vastly simpler to me than whatever solution comes up every few years (Backbone, Knockout, Angular, React, modifying the language itself, etc). There must be something profoundly different with the way I think. It even expresses itself in the function naming. They call updating innerText “render”. You’re not rendering anything. At most, the browser is, but so is everything else it does related to painting. It feels like a desperate attempt to complicate what is one of the simplest DOM functions. It really baffles me.
- duxup 2y agoIn simple applications it is easy. More complex it is not easy.
- tambourine_man 2y agoI’ve been writing web apps for easily 25+ years. Never have I reached for React and friends voluntarily. But again, I know I’m in a minority. I’m just not completely sure why.
- duxup 2y agoYou could work for 50 years and never need those… it just depends on what you’re creating / how many devs and so on. I know some guys who over the years wrote their own framework. It works great… for them.
- tambourine_man 2y agoRight, the only thing that convinces me is team and hiring dynamics. But that’s not what these tools advertise. It’s always like: you have dozens of interactive controls in this view, it’s getting out of hand, you should use this language that compiles to HTML and JavaScript and carry all these dependencies. To which I always reply: no thanks, I rather deal with the dozens of controls.
- beders 2y agoI've been enjoying "signals" in the form of re-frame subscriptions for many years now. They solve a neat subset of problems in front-end developments. But they don't solve all of them. Adding it to JavaScript as language construct is unnecessary.
- tommiegannert 2y agoHmm, if we can optimize the reactive state management in all web apps, that sounds cool. If this is to be a base for VueJS, it should handle deep changes. They have a note about support Map and Set, but being able to to control depth is nice in VueJS. (I'd say watch() should be deep by default, since non-deep is an optimization that can lead to accidental inconsistent state.) Streams. Generally, I find RxJS backwards. Usually you just need "state", so that should be the easiest thing to implement. But I can't deny that the programming model is beautiful. Standardizing "state" without also considering streams seems odd to me. The "computed" creates a pipeline of updates, very similar to one you'd do with a map over a stream. If RxJS didn't already exist, I probably wouldn't have cared about this duality. Async. Sure, signals can be synchronous, but Computed should definitely play well with async functions. This is a big shortcoming in VueJS (that people work around on their own.) That also implies handling "pending computation" gracefully for debuggability. I see there's a "computing" state, but this would have to be surfaced to be able to debug stuck promises. Exceptions. I like the idea of .get() rethrowing exceptions from Computed. VueJS is a bit vague on that front, and just stops.
- nullvoxpopuli 2y ago> it should handle deep changes. these can be implemented in userland via proxy -- and I think probably should, as is proven by this collection of utils: https://twitter.com/nullvoxpopuli/status/1772669749991739788 https://twitter.com/nullvoxpopuli/status/1772669749991739788 If we were to try implementing everything as reactive versions, there'd be be no end, and implementations couldn't keep up -- by pushing reactive Map/Set/etc to userland/library land, we can implement what we need when we need it incrementally, built on the solid foundation of the signal primitives. > since non-deep is an optimization that can lead to accidental inconsistent state. conversely, deep-all-the-time is a performance hit that we don't want to be default. Svelte and Ember take this approach of opt-in-deep reactivity.
- _heimdall 2y agoI don't think signals will help move development away from further complexity, and that's really what we need today. There's a fundamental question of why modern sites/apps reach for patterns like signals, memorization, hybrid rendering patterns, etc. I wouldn't begin to claim I have all the answers, but clearly there are gaps in the platform with regards to the patterns people want to implement and I'm not sure that jumping to signals as a standard helps better understand whether its the platform or our mental models that need updating to get back in sync. Personally I've found code much easier to maintain when the frontend is only responsible for state that truly is temporary and doesn't live on the back end at all. For me any persisted state belongs on the server, as does any rendering that depends on it. This largely makes signals unnecessary, very few apps have such complex temporary state that I need a complicated setup to manage it.
- itsjustme2 2y agoAm I the only one that thinks the vanilla js example is actually easier to read and work with? - "The setup is noise and boilerplate heavy." Actually the signals example looks just as noisy and boilerplate heavy to me. And it introduces new boilerplate concepts which are hard for beginners to understand. - "If the counter changes but parity does not (e.g. counter goes from 2 to 4), then we do unnecessary computation of the parity and unnecessary rendering." - Sounds like they want premature memoization. - "What if another part of our UI just wants to render when the counter updates?" Then I agree the strawman example is probably not what you want. At that point you might want to handle the state using signals, event handling, central state store (e.g. redux-like tools), or some other method. I think this is also what they meant by "The counter state is tightly coupled to the rendering system."? Some of this document feels a little repetitive. - "What if another part of our UI is dependent on isEven or parity alone?" Sure, you could change your entire approach because of this if that's a really central part of your app, but most often it's not. And "The render function, which is only dependent on parity must instead "know" that it actually needs to subscribe to counter." is often not an unreasonable obligation. I mean, that's one of the nice things about pure computed functions- it's easy to spot their inputs.
- duxup 2y agoI agree the initial example is easier to read, but it has problems as stated.
- leononame 2y agoWhy do you think this is premature memoization? This is an example, boiled down to a simple function. Do you think people just came up with the use case for this without ever having needed it? I think an effort in standardizing signals, a concept that is increasingly used in UI development is a laudable effort. I don't want to get into the nitty gritty about what is too much boilerplate and whether you should build an event system or not, but since signals are something that is used in a variety of frameworks, there might be a good reason to it? And why not make an effort and standardize them over time?
- 38 2y ago
- vbezhenar 2y agoI didn't understand the example in the linked README. // A library or framework defines effects based on other Signal primitives declare function effect(cb: () => void): (() => void); What library? What framework? I lost here. What's effect? effect(() => element.innerText = parity.get()); How does effect knows that it needs to call this lambda whenever parity gets changed? Will it call this lambda on any signal change? Why this talk about caching then? Probably not. Anyway I think that signal idea is sound, if I understood correctly what the authors tried to convey. My main issue with those decoupling architectures is that once your application is complex enough, you will get lost trying to figure out why this particular event being emitting. Ideally signals should fix this by modifying stacktrace, so when my callback is being called, it'd already contain a stacktrace of the code which triggered that signal in the first place.
- troupo 2y ago1. effect is any function you want to invoke 2. with signals the dependency tracking mechanism knows what values need to be recalculated and as a result the system knows which functions to call again
- throwitaway1123 2y ago> What library? What framework? I lost here. What's effect? There are various libraries that export a function called effect which allows you to run arbitrary code in response to a signal update. The Preact docs have a great primer on signals and effects: https://preactjs.com/guide/v10/signals#effectfn https://preactjs.com/guide/v10/signals#effectfn As I understand it, these effect functions run the callback once initially to see which signals were accessed while the callback was executing, and then call the callback again whenever the signals it depends on update. As long as signal access is synchronous and single-threaded, you know that if a signal was accessed during the callback's execution that the callback should be subscribed to those signals. > How does effect knows that it needs to call this lambda whenever parity gets changed? Will it call this lambda on any signal change? You can do this with getters [1], where the effect function tracks which properties of the signal were accessed in a getter method (I believe Vue historically did this in version 2), but you can also track object access using proxies [2]. The example from the proposal simply has a 'get' method that is called to access the value of the signal, and executing this method allows dependencies to be tracked. [1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... [2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- jupp0r 2y agoThis is a horrible idea. Instead of building some dependency tracking into this niche feature of the language, JS should come up with a generic way of enabling framework developers to clean up resources without putting the burden on users of their API to manually do this.
- henriquez 2y ago“Lets make my random UI state tracking framework part of the JavaScript spec”
- ttfkam 2y agoLooks like Svelte 5 only somehow worse?
- bastawhiz 2y agoThe proposal is very clear that it's not trying to be pretty, it's trying to be sensible and correct so that frameworks like Svelte can build on top of them and work interoperably with other libraries and frameworks.
- meindnoch 2y ago"let's bake my current framework du jour into the standard library!" It's a bit like tattooing your girlfriend's name onto yourself.
- Sammi 2y agoExcept that's not what this is doing. It's baking a building block into the standard library, that most frameworks have converged on using. Promises became widely used, then they got included in the standard library. This is like that.
- nikeee 2y agoBack in the days there was an effort to put observables in the language because they were popular (and rxjs was, too). Glad that didn't happen. And I think everybody else is, too. Maybe we should keep that in mind when standardizing features of frameworks.
- Offler 2y agoThey weren't used in virtually every single frontend framework though while Signals are
- junon 2y agoRelated is S.js: https://github.com/adamhaile/s https://github.com/adamhaile/s I love signals. I prefer them when making UIs over any other primitive (besides, perhaps, the cassowary constraint algorithm). I try to replicate them in every language I use, just for fun. I also don't believe they belong in the Javascript language whatsoever. Let the language be for a while, people already struggle to keep up with it. TC-39 is already scaring away people from the language.
- recursive 2y agoIf people are getting scared away from javascript, imagine what a popular one would look like!
- da39a3ee 2y agoThis article is missing a "What are signals" section. And yes, this does not do the job: > Within JS frameworks and libraries, there has been a large amount of experimentation across different ways to represent this binding, and experience has shown the power of one-way data flow in conjunction with a first-class data type representing a cell of state or computation derived from other data, now often called "Signals".
- readline_prompt 2y agoCurious, what about using Proxies for handling state?
- CanaryLayout 2y agoOh God why.
- nyanpasu64 2y agoIs this like QML property binding?
- nojvek 2y agoOh man. This sounds complicated. The hard part of signals is similar to over complicating events. It’s hard to debug what is going on and what to fix when things go wrong.
- qudat 2y ago> The current draft is based on design input from the authors/maintainers of Angular, Bubble, Ember, FAST, MobX, Preact, Qwik, RxJS, Solid, Starbeam, Svelte, Vue, Wiz, and more… This is primarily the only handful of consumers of this stdlib.
- Offler 2y agoThat's basically every major framework apart from React and it includes some major React libraries.
- endgame 2y agoFrom a first look, signals seem to parallel event/behaviour-style functional reactive programming (FRP). Hopefully some useful ideas from the FRP world can be brought across.
- nikitaga 2y agoWhy does it need to be a part of the language? This could be a library. There are such libraries. They are small, so including them in your code is no big deal. Adding this to the language should not even be a goal. Thinking that the current crop of JS UI libraries designed their signals in such a good way that it needs to become a part of the language is hubris. Signals have many possible implementations with different tradeoffs, and none of them deserve to have a special place in the JavaScript spec. Before these libraries used signals, they or their predecessors used virtual DOM. Luckily, that didn't become part of JS, but how are signals any different? They aren't. The argument for making them standard is even worse than for virtual DOM. Are we just going pile every fad into a runtime that basically has no way to dispose of no-longer-wanted features without breaking the web? That is quite short sighted.
- imbnwa 2y agoRemember the Observable proposal?
- tengbretson 2y agoThe Observable proposal made a stronger case in my opinion, since Observables provide an interface that is functionally unique and useful for the boundaries between app logic and libraries, so a single standard approach has benefits. Signals on the other hand live right where application state binds to the ui. Is this really somewhere that people are patching together a hodge podge of libraries that need to use a consistent api? I'm not so sure.
- Offler 2y agoSignals are used in every framework except React. Observables weren't. That's a huge difference.
- Sammi 2y agoThere's the old one that fizzled out: https://github.com/tc39/proposal-observable https://github.com/tc39/proposal-observable And there's the new one which seems to be getting implemented in node right now: https://github.com/WICG/observable https://github.com/WICG/observable
- dboreham 2y agoFFS there's already something named signals, since c. 1972.
- fwlr 2y agoWhen they added Promises to JavaScript, I bristled at the thought that I might have to start writing `new Promise` everywhere. In practice, I can count on two hands the number of times I’ve written `new Promise`. What did happen, though, is I started to write `.then` a whole lot more, especially when working with third party libraries. In the end, the actual day-to-day effect of the Promise addition to JavaScript was it gave me a fairly simple, usually solid, and mostly universal interface to a wide variety of special behaviors and capabilities provided by third party libraries. Whether it’s a file read or an api request or a build step output, I know I can write `.then(res => …)` and I’m already 50% of the way to something workable. If this Signal proposal can do something similar for me when it comes to the Cambrian explosion of reactive UI frameworks, I am in favor! What’s more, maybe it will even help take reactivity beyond UI; I’ve often daydreamed about some kind of incrementally re-computed state tree for things other than UI state.
- jonathanlydall 2y agoI assumed the Promises was added primarily so that async/await could be added, which is where the really substantial quality of life improvement is. In practice you rarely need to explicitly go “new Promise” yourself. While .then in initial promises was a great improvement over nested delegates and is fine for simple chained promises, once you start conditionally chaining different promises or need different error handling for particular chains in the promise, or wanting to do an early return, the code can become much harder to read and work with. With async/await though you just write the call essentially as if it’s not a promise and can easily put try/catch around particular promise calls, easily have early returns, etc.
- srcreigh 2y agoI’m in favour. Mobx is great. This will focus efforts on making better devtools.
- Too 2y agoThe examples only show simple values. What happens when mutating nested objects and arrays? Other frameworks usually struggle a lot with this. With workarounds like having to override equality functions in useMemo() or call .set after a mutation even if you pass in the same instance as before.
- moi2388 2y agoBut the vanilla code is much cleaner and nicer to read and reason about than the proposal?! Seriously the JavaScript ecosystem is so strange..
- Too 2y agoThis looks sufficiently advanced to warrant some language support. This could be a much more powerful feature if signal-dependencies were discovered statically, rather than after use in runtime. If you’ve reached the point where you agree that the library should be standardized, why not take it even further to integrate it even more?
- sapling-ginger 2y agoBecause there's no rule that says signals should ever be created at the top level assigned to a const variable. You could create signal objects dynamically based on user input, no current proposal or implementation prevents this. So there's no way to do static analysis on signal graphs.
- sattoshi 2y agoThe first and only question that matters: is this useful as a primitive? Im inclined to say no. Signals seem like they are a UI concept, primarily. Just use any signal lib you want. Utility libraries dont really need to understand signals.
- gloosx 2y agoTo be as a long-time react.js user – these examples look like a kinda weird mix of declarative with some bitter imperatives. Like, foo.set depending on foo.get and having to manually set element innerText inside the side-effect, eww, I can only imagine how messy it can get for a somewhat more complex application. React boilerplate for this case looks so much better in my opinion, take a look ``` function Component() { const [counter, tick] = useReducer(st => st + 1, 0) useEffect(() => setInterval(tick, 1000)) return counter % 2 ? 'odd' : 'even' } ``` Three lines, declarative, functional, noice.
- recursive 2y agoFunctional usually means the output can only depend on the input. But this is depending on some external state getting smuggled in through a hook. FWIW some people prefer the alternatives over this.
- gloosx 2y agoThis not really correct, the useReducer hook is not some external state which is smuggled in. It is an actual input for the reconciler which defines an output of this component, so it is perfectly functional even by your definition.
- recursive 2y agoThe value counter changes in subsequent invocations. Maybe react redefined some standard terminology, but this is really straightforward. If useReducer is not pure, and it's not, any function that calls it is impure.
- silent_cal 2y agoI am amazed at the ability of the JS community to consistently make things more and more complicated.
- pjmlp 2y agoSignals only made sense in the past of desktop programming languages, because the ones on mainstream lacked lambdas and closures. Smalltalk, and Lisp derived ones did just fine without them. Modern JavaScript already has them as well, no need for what is basically a closure with a listeners list.
- deleted 2y ago[deleted]
- naasking 2y agoI don't quite get how these signals intend to be efficient while using pull-based evaluation. A pull-based model potentially requires touching the entire object graph to check if one value needs to be recomputed on get(). It makes for a simple but inefficient implementation.
- wseqyrku 2y agoI'd be much more comfortable if they were standardizing around react or something. What is the advantage of this being a built-in feature compared to a lib for folks to actual use first hand before proposing it upstream?