News for hackers. Stuff that matters.
Re:Better Promises in JavaScript by mnr on Monday September 24, 2018 @08:38AM (#18057154)
This is already a feature in Vanilla.js [1] in the "Parentheses" module.

Example:

  const lines = (await fetch(myUrl)).text().split('\n');
[1] http://vanilla-js.com/

Edit: magic-promises promotes all accessed properties to magic-promises as well, and performs magic on functions, so it's not exactly the same, but I'm not sure if I'd want to add the proxy overhead to my code just to make my code more "fluent".

Re:Better Promises in JavaScript by franciscop on Monday September 24, 2018 @07:27PM (#18062360)
As explained .text() returns a promise, and the fact that many people don't know that and that your 1-line solution does not work is a strong indication that my solution is helpful!

With magic-promises you don't need to worry about whether something regurns a promise or not. See fs-array, some methods will return promises and some won't, but you can just treat them all the same.

Re:Better Promises in JavaScript by mnr on Tuesday September 25, 2018 @07:41AM (#18065421)
I thought I was so clever! But yes I see how it's very different. In general, magic (or using Proxy) scares me, but I'm warming up to the idea here.
Re:Better Promises in JavaScript by zebracanevra on Monday September 24, 2018 @10:48AM (#18058139)
fetch's Response.text also returns a Promise, so you'd have to await twice:

  const lines = (await (await fetch(myUrl)).text()).split('\n');
Re:Better Promises in JavaScript by mikewhy on Monday September 24, 2018 @03:38PM (#18060734)
I've always just added an overload:

    function fetchText(input?: string | Request, init?: RequestInit) {
      return fetch(input, init).then(x => x.text())
    }

    function fetchJson(input?: string | Request, init?: RequestInit) {
      return fetch(input, init).then(x => x.json())
    }
Re:Better Promises in JavaScript by mnr on Monday September 24, 2018 @11:16AM (#18058376)
Shucks, I can see how it becomes verbose.
Re:Better Promises in JavaScript by felixfbecker on Monday September 24, 2018 @07:37AM (#18056795)
I love it when articles just put statements out like "This syntax would be much better, wouldn't it?" and then just assume the answer is obviously yes and don't find the need to provide any arguments for that.

I disagree. Explicit is better than implicit.

Re:Better Promises in JavaScript by franciscop on Monday September 24, 2018 @08:16AM (#18057015)
I agree, explicit is better than implicit. But redundant is worse than non-redundant. This library just provides syntax sugar to make things cleaner. There are many times that arbitrary decisions have been taken. Why cannot you wait to an array of promises? Wouldn't that be explicit and clear?
Re:Better Promises in JavaScript by monsieurbanana on Monday September 24, 2018 @12:06PM (#18058840)
Awaiting an array of promises looks neat, but it has a (small?) caveat: you can't do the same for the non-await version. You can't do `[...].then()`.

I'm less fan of the second proposition. Imagine someone seeing that snippet on internet and copying it: he would have no way of knowing that ".text()" is actually a promise and could potentially be making more I/O calls than he thought.

Re:Better Promises in JavaScript by marcodave on Monday September 24, 2018 @07:51AM (#18056870)
It's lovely how node.js started with callback nesting hell, then to promise chaining, then to async/await, then to "magic" libraries like this.

How long since someone will figure out how to get rid of the (error-prone) await keyword, and go back full circle on plain old synchronous-style syntax?

Re:Better Promises in JavaScript by scottmf on Tuesday September 25, 2018 @04:41PM (#18070302)
You might find this library interesting https://github.com/scf4/callbaxx
Re:Better Promises in JavaScript by woah on Monday September 24, 2018 @11:40AM (#18058603)
This library has some very minor syntax sugar. Async/await is currently the most ergonomic abstraction for handling single-thread concurrency.
Re:Better Promises in JavaScript by WorldMaker on Monday September 24, 2018 @02:13PM (#18059934)
Also, the examples here aren't as "unergonomic" as the article suggests with async/await.

    const lines = await fetch(...).then(res => res.text()).then(res => res.split('\n'))
Any use of .then in async/await is a code smell.

The obvious single line refactor (as presented in other threads):

    const lines = (await (await fetch(url)).text()).split('\n')
But a clearer refactor is simply multiple lines to make each "step" clear as mud:

    const response = await fetch(url)
    const text = await response.text()
    const lines = text.split('\n')
Yes, it's a bit over-verbose than the one liner, but ergonomically it is step-by-step imperative programming just like Grandma C++ used to bake, and few would argue that it isn't readable old-fashioned ergonomics.

Promise.all is a tougher thing to get "ergonomics" from, but more often than not, a refactor to a "classic" for loop pattern is often clearer. The semantics change, unfortunately, yet more often than not the clearer "one-thing-at-a-time" of the simpler refactor is easier to debug, less harsh on called services, less pressure on client memory, and simpler to progress report.

Instead of:

const responses = await Promise.all(urls.map(url => fetch(url)) const texts = await Promise.all(responses.map(response => response.text()) for (let text of texts) { doSomething(text) }

Try:

    for (let url of urls) {
      const response = await fetch(url)
      const text = await response.text()

      doSomething(text)

    }

Again, the semantics change: instead of waiting for all of them to complete as massively parallel it operates a bit more "synchronously" one at a time. But the benefits again are that ergonomically it is much clearer what each individual step is, how much work has been done, roughly how much work is left to do. Additionally, you aren't creating a massive array of the text of every response before operating on each text, which can be a big deal for performance memory pressure. More often than not, I've seen cases where the simpler for (let of)/await pattern here is more performant than all the parallel calls simply because of the drop in this memory pressure.

For cases where you do need more of the parallelism, ESNext AsyncIterable is a better plan than Promise.all(), and affords the for-await pattern:

    for await (let response of responsePromiseIterator) {
      const text = await response.text()
      doSomething(text)
    }
Which again, is more ergonomic overall, often easier to get the performance right than Promise.all(), and easy enough to change to different parallel strategies because the code stays the same regardless of the scheduler used to build your async iterator.
Re:Better Promises in JavaScript by Boulth on Monday September 24, 2018 @06:51AM (#18056585)
Very cool although I'm missing the explanation of how this is done. Are you using Proxies like here: https://curiosity-driven.org/monads-in-javascript#chain ?
Re:Better Promises in JavaScript by franciscop on Monday September 24, 2018 @08:18AM (#18057029)
Exactly! The whole source code is basically Proxy() functions: https://github.com/franciscop/magic-promises/blob/master/mag...
Re:Better Promises in JavaScript by schindlabua on Monday September 24, 2018 @05:00AM (#18056059)
What Javascript really needs is monads and do-notation. Can I use Haskell on the web yet?
Re:Better Promises in JavaScript by girvo on Monday September 24, 2018 @06:40AM (#18056528)
Yeah, it’s called Purescript and it’s quite lovely. Give it a look!
Re:Better Promises in JavaScript by Boulth on Monday September 24, 2018 @06:48AM (#18056571)
As much as I like PureScript (it's like a cleaned up Haskell!) it has some issues, e.g. with performance (as it uses instanceof a lot).

There is also this minor thing that that the compiler is not written in PureScript.

Re:Better Promises in JavaScript by franciscop on Sunday September 23, 2018 @05:49PM (#18053457)
Exploring the reasons why I launched a library to improve async-heavy workflows which falls back to normal promises. It is very useful specially for tool authors, see the library I also published recently `fs-array` using `magic-promises`.
Re:Better Promises in JavaScript by rhinoceraptor on Monday September 24, 2018 @01:10PM (#18059400)
Promises were a giant mistake. How many times have you had a programming error (TypeError, ReferenceError, etc.) suppressed by your operational error handling code?
Re:Better Promises in JavaScript by everdimension on Monday September 24, 2018 @05:10AM (#18056098)
IIRC promises already have a `map` method which is synonymous to the `then` method.
Re:Better Promises in JavaScript by franciscop on Monday September 24, 2018 @05:58AM (#18056335)
Not with native promises. You have the Promise.all([...]), which is explained in the article but no .map() AFAIK
Re:Better Promises in JavaScript by lisq199 on Monday September 24, 2018 @11:20AM (#18058410)
I think RxJS already solves the problem.

https://github.com/ReactiveX/rxjs

Re:Better Promises in JavaScript by woah on Monday September 24, 2018 @11:34AM (#18058555)
Solves what problem? The article is about some very minor syntax sugar, while you are plugging a tangentially related library with a whole raft of its own abstractions. I’m struggling to understand the context here.
Re:Better Promises in JavaScript by franciscop on Monday September 24, 2018 @07:31PM (#18062389)
Suggesting RxJS in this context IMO is like when someone suggests doing `const $ = sel => [...document.querySelectorAll(sel)];` as helpful syntax sugar for the 20-lines of JS project but they get shut down because it's no React.