Live data from Hacker News

A proposal to add signals to JavaScript

github.com

301–310 of 336 posts

Re: A proposal to add signals to JavaScript

#301
post #190

Earlier quoted context omitted.

> 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.

> It already is, obviously. But how is SolidJS supposed to work with other non-SolidJS code? Who actually writes code like this? People use some signal graph library for application code typically, I’ve never seen anyone mixing SolidJs with MobX in application code or as a consequence of a library dep.

Let me offer you a scenario: you want to build a UI web component that uses state, but you want it to be usable in both Svelte and React (with solidjs). The current situation is that it's a massive pain in the ass, because you have to move all of the state out of your code into a "driver" module that you can swap out for each of the frameworks you want to target. The entire architecture of your library is made worse (less readable/maintainable, probably less performant, harder to contribute to) in order to have a single set of UI code.

All of that goes away when the plumbing for handling state is standardized by the runtime.

Re: A proposal to add signals to JavaScript

#302
post #288

Earlier quoted context omitted.

The 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', (…

If 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.

But 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.

Re: A proposal to add signals to JavaScript

#303

Earlier quoted context omitted.

If each await was to a setTimeout call waiting 1000ms, awaiting all 3 would take approximately 3000ms. If you await a Promise.all with an array of the promises, it will take approximately 1000ms. In summary, using individual awaits runs them serially, while Promise.all runs them concurrently. If you’re doing CPU bound work without workers, it doesn’t make much of a difference, but if you’re doing I/O bound tasks, lik…

I get what you're saying, but that's just not how it works in my experience. I've got a repro in codepen. What am I missing? https://codepen.io/tomtheisen/pen/QWPOmjp function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function test() { const start = new Date; const promises = Array(3).fill(null).map(() => delay(1000)); for (const p of promises) await p; const end = new Date; console.…

What I imagined from your initial description is that you were doing the following:

  for (var i = 0; i 
However (as you are possibly well aware), this line in your example is starting all the work immediately and essentially in parallel:

  const promises = Array(3).fill(null).map(() => delay(1000));
So the timing of your for...of loop is that the first element probably takes about 1000ms to complete, and then the other two seem to happen instantly.

Promise.all is just an alternative to writing the for...of await loop:

  await Promise.all(promises); 
I guess it relies on you already being familiar with the Promise API, but I feel that Promise.all() has slightly less cognitive load to read and its intent is more immediately clear.

A strong case for preferring the Promise.all() is that Promise.allSettled(), Promise.any() and Promise.race() also exist for working with collections of promises, and unlike Promise.all(), they would not be so easily reproduced with a one liner for...of loop, so its not unreasonable to expect that JS developers should be aware of Promise.all(), meaning there is no reason for it not to be the preferred syntax for the reasons I stated above.

Re: A proposal to add signals to JavaScript

#305

Earlier quoted context omitted.

If each await was to a setTimeout call waiting 1000ms, awaiting all 3 would take approximately 3000ms. If you await a Promise.all with an array of the promises, it will take approximately 1000ms. In summary, using individual awaits runs them serially, while Promise.all runs them concurrently. If you’re doing CPU bound work without workers, it doesn’t make much of a difference, but if you’re doing I/O bound tasks, lik…

I get what you're saying, but that's just not how it works in my experience. I've got a repro in codepen. What am I missing? https://codepen.io/tomtheisen/pen/QWPOmjp function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function test() { const start = new Date; const promises = Array(3).fill(null).map(() => delay(1000)); for (const p of promises) await p; const end = new Date; console.…

You're starting all three promises, then waiting for the first one to finish, then waiting for the next one, then waiting for the last one. But because they were all started at the same time, they'll be run in parallel.

Whereas if you started one promise, waited for it to finish, then started the next and so on, it would take the three seconds as they won't be run in parallel.

The code you've written can be seen as a "poor-man's" Promise.all, in the sense that it's doing roughly the same thing but less clearly. It also behaves slightly differently in terms of rejections: if the final promise in the Promise.all version rejects immediately, then the whole promise will fail immediately. However, in your version, if the final promise rejects, that rejection won't be evaluated by the await (and therefore thrown) until all the other tasks have completed.

For reasons of clarity and correctness, therefore, it's usually better to just use Promise.all rather than awaiting a list of already-started promises in sequence.

Re: A proposal to add signals to JavaScript

#306
post #305

Earlier quoted context omitted.

I get what you're saying, but that's just not how it works in my experience. I've got a repro in codepen. What am I missing? https://codepen.io/tomtheisen/pen/QWPOmjp function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function test() { const start = new Date; const promises = Array(3).fill(null).map(() => delay(1000)); for (const p of promises) await p; const end = new Date; console.…

You're starting all three promises, then waiting for the first one to finish, then waiting for the next one, then waiting for the last one. But because they were all started at the same time, they'll be run in parallel. Whereas if you started one promise, waited for it to finish, then started the next and so on, it would take the three seconds as they won't be run in parallel. The code you've written can be seen as a…

In order to use `Promise.all`, you'd still have to construct all the promises without awaiting them. That seems like the whole foot-gun and cognitive load right there.

But the early rejection is a concrete improvement over the "poor-man's" version. I'm sold.

Re: A proposal to add signals to JavaScript

#307

Earlier quoted context omitted.

I get what you're saying, but that's just not how it works in my experience. I've got a repro in codepen. What am I missing? https://codepen.io/tomtheisen/pen/QWPOmjp function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function test() { const start = new Date; const promises = Array(3).fill(null).map(() => delay(1000)); for (const p of promises) await p; const end = new Date; console.…

What I imagined from your initial description is that you were doing the following: for (var i = 0; i However (as you are possibly well aware), this line in your example is starting all the work immediately and essentially in parallel: const promises = Array(3).fill(null).map(() => delay(1000)); So the timing of your for...of loop is that the first element probably takes about 1000ms to complete, and then the other t…

Ok, I'm a believer. I misled myself into thinking there was more going on with Promise.all than there really was. I'm mildly averse to allocating unnecessary arrays. But this is mostly superstition rather than measurable performance concern.

Promise.allSettled has a poor-mans implementation too. But the others really don't have such a thing.

My impression is that Promise.all() is kind of nice, but it's really not that big a deal or important. If it didn't exist, you could get the same happy-path code behavior without really even changing the size of the calling code.

But there's nothing wrong with it really. On balance, it seems slightly nicer than the poor-man's re-implementation. In the last 5 years, I might have been able to use it maybe twice.

Re: A proposal to add signals to JavaScript

#308
post #190

Earlier quoted context omitted.

> It already is, obviously. But how is SolidJS supposed to work with other non-SolidJS code? Who actually writes code like this? People use some signal graph library for application code typically, I’ve never seen anyone mixing SolidJs with MobX in application code or as a consequence of a library dep.

Let me offer you a scenario: you want to build a UI web component that uses state, but you want it to be usable in both Svelte and React (with solidjs). The current situation is that it's a massive pain in the ass, because you have to move all of the state out of your code into a "driver" module that you can swap out for each of the frameworks you want to target. The entire architecture of your library is made worse…

Perhaps Svelte, Solid, React, et al should form a working group and hammer out an interopt standard

Re: A proposal to add signals to JavaScript

#309
post #294
post #243

Earlier quoted context omitted.

They don't fire off each other, they simply depend on each other like functions do: a = () => 42 b = () => a() - 1 c = () => a() + b() * 2 It isn't a bigger nightmare than debugging pure functions. The source for `c` is `a` and `b`. All signal values (as proposed) will be lexically available in a body of a dependent signal, so there's no hidden registry to navigate anyway. If in-browser IDEs want to record a call tre…

There is still a watch() mechanism that from a consumers point of view hide the originating event of an update. Otherwise if all you wanted was functions, just use functions. When watch fires out of control, you need debugging tools to understand why your render() function is being invoked more often than it should. This type of problem happens all the time in react and you need to trace upwards to find that 7 compon…

Signals are basically lazy functions. You can't "just" use functions if performance is a concern, cause that's the least efficient way to keep everything consistent.

Since watching seems(?) to be synchronous in the proposal, why do you think extra debugging tools are needed? You can breakpoint into render() with a regular debugger and look at the stack trace.

Re: A proposal to add signals to JavaScript

#310
I 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.
Post reply on HN