
Node v8.0.0 Released - petercooper
https://nodejs.org/en/blog/release/v8.0.0/
======
nailer
Short ver: async await is now in an LTS release of node. Anything that returns
a promise can now be run inline - ie, no endless .then() chaining - provided
you've started an async context:

    
    
      const writeFile = util.promisify(fs.writeFile),
        request = util.promisify('superagent'),
        stat = util.promisify(fs.stat),
        sorts = require('sorts'),
        log = console.log.bind(console)
    
      const getJeansAndSaveThem = async function(){ 
        var jeans = await request.get('https://example.com/api/v1/product/trousers').query({
          label: 'Levi Strauss', 
          isInStock: true,
          maxResults: 500
        }).end()
        jeans = jeans.sort(sorts.alphabetical)
        await writeFile('jeans.json', jeans)
        const status = await stat('jeans.json');
        log(`I just got some data from an API and saved the results to a file. The file was born at ${status.birthtime}`)
      }
    

Note: you should add error handling, I'm new to async/await and this code is
to demonstrate a concept on HN, not to run your life support system. ;-)

~~~
ujal
There should also be something like

    
    
      awaitAll 

to replace

    
    
      await Promise.all 

calls.

~~~
steve_adams_86
You can make it yourself fairly easily I guess:

    
    
        const awaitAll = Promise.all.bind(Promise);
    
        async function foo() {
            var [val1, val2] = await awaitAll([func1, func1]);
        }
    

It isn't ideal but it's a little cleaner

~~~
nailer
+1. I'm a big fan of top level function binds to remove boilerplate and keep
code readable:

    
    
      const log = console.log.bind(console), 
        query = document.querySelector.bind(document),
        queryAll = document.querySelectorAll.bind(document);

~~~
RReverser
You don't need to bind `console.log` by the way (at least not in any recent
version of Node.js or browsers).

------
SparkyMcUnicorn
"Note that, when referring to Node.js release versions, we have dropped the
"v" in Node.js 8. Previous versions were commonly referred to as v0.10, v0.12,
v4, v6, etc. In order to avoid confusion with V8, the underlying JavaScript
engine, we've dropped the "v" and call it Node.js 8."

I was wondering how this would be handled. I guess old habits die hard since
this article title includes the "v".

~~~
agrippanux
Odd then that nvm still calls it v8.0.0

------
petercooper
For anyone not in the JS/Node worlds, this is a significant release that
people are particularly excited about. It was also delayed somewhat due to
wanting to align with V8 which should, however, be totally worth it :-)

Other relevant posts digging into new features include
[http://codingsans.com/blog/node-8](http://codingsans.com/blog/node-8) and
[https://blog.risingstack.com/important-features-fixes-
node-j...](https://blog.risingstack.com/important-features-fixes-node-js-
version-8/)

------
flavio81
For me, this one brought happiness:

 _Node.js 8.0.0 includes a new util.promisify() API that allows standard
Node.js callback style APIs to be wrapped in a function that returns a
Promise. An example use of util.promisify() is shown below._

This is great stuff. This enables writing code using async and await at all
times, which is what any sane developer would do when writing code for
Node.js.

~~~
idbehold
Promisify is a super simple function to write yourself though.

    
    
      const promisify = (fn, ctx) => (...args) =>
        new Promise((resolve, reject) =>
          fn.apply(ctx, [ ...args,
            (err, data) => err ? reject(err) : resolve(data)
          ])
        )

~~~
elmigranto
Almost. Don't forget about the case where callback receives multiple
arguments, and the fact that someone might decide to change the API for
callback signature like `(err, result)` to `(err, result, stats)`, for
example.

~~~
idbehold
Promises only support a single success value so if you're "promisifying"
something then you're only going to the second argument as the resolved value.
The new util.promisify() doesn't provide said functionality [1] will only
resolve the second argument [2] unless you define a custom function on the
original function.

[1]:
[https://nodejs.org/api/util.html#util_util_promisify_origina...](https://nodejs.org/api/util.html#util_util_promisify_original)

[2]:
[https://github.com/nodejs/node/blob/ef16319effe396622666268c...](https://github.com/nodejs/node/blob/ef16319effe396622666268cd8100ad8d586c4ee/lib/internal/util.js#L204-L245)

~~~
elmigranto
A bunch of functions in core return multiple things to callback. A lot more in
userland do the same. Spec or not, that is still something that needs to be
accounted for.

~~~
idbehold
Those are handled by `util.promisify()` by having the original function define
special properties on itself `Symbol('util.promisify.custom')` and
`Symbol('customPromisifyArgs')`. But it's not something handled by default
(e.g. resolving an array if the callback gets more than 2 arguments passed to
it).

~~~
bfred_it
But why. If you're gonna take special steps to handle `util.promisify` you
might as well just offer a Promised API and skip `util.promisify`

------
elzi
I know there's much bigger things in this release to be excited about, but I'm
so happy they're allowing trailing commas in function args/params.

~~~
koolba
Curious why?

I get the usefulness for arrays and object declarations. Particular to have
cleaner diffs. But why for function calls?

~~~
epidemian
> Particular to have cleaner diffs. But why for function calls?

Exactly the same reason :)

~~~
koolba
I suppose but that's usually an indication that an object would be more apt.
If you have enough parameters that it needs to be wrapped, they're probably
hard to track too.

~~~
piezoney
Well no, since you can use object destructuring.

const fn = ( { arg1 = '', arg2 = [], arg3 = true } = {} ) => { }

~~~
scottmf
But isn't this already valid with trailing commas?

------
neovive
This is exciting news! I'm a long-time LAMP developer (now mostly Laravel) and
have been experimenting with NodeJS for an upcoming API project. As Javascript
becomes a larger part of each new project, using one language throughout the
entire stack is becoming much more compelling.

Is Express still considered the de facto web framework for NodeJS? Or are
other frameworks better suited for someone used to the "batteries-included"
philosophy of Laravel. I'm watching the new "Learning Node" course from WesBos
since he covers async/await and Express seems very similar to most MVC
frameworks.

~~~
Can_Not
My passion right now is feathers+nuxt+vuejs. If you're really wanting to keep
the "Laravel" feeling though, there is also adonisjs.

~~~
neovive
AdonisJS is definitely very close to Laravel. I'm not a big fan of the
generator syntax, but I assume they will migrate to async/await with the Node
v8 announcement.

------
ianstormtaylor
Does anyone have a link to better explanation of the changes to `debugger`?

> The legacy command line debugger is being removed in Node.js 8. As a command
> line replacement, node-inspect has been integrated directly into the Node.js
> runtime. Additionally, the V8 Inspector debugger, which arrived previously
> as an experimental feature in Node.js 6, is being upgraded to a fully
> supported feature.

It sounds like `node debug` will no longer work? But it is replaced with
something that's better? What is `node-inspect` and where can I learn about
it?

~~~
rattray
Good questions – the new facilities are improvements AFAICT:

    
    
        node --inspect index.js
    

Or

    
    
        node --inspect --debug-brk index.js
    

then open `chrome://inspect` in Chrome.

[https://medium.com/@paul_irish/debugging-node-js-
nightlies-w...](https://medium.com/@paul_irish/debugging-node-js-nightlies-
with-chrome-devtools-7c4a1b95ae27)

~~~
sigil
Can I debug node 8 from the command line, or do I need X / chrome now?

~~~
rattray
You can also debug, to a limited degree, from the command line:

[https://nodejs.org/api/debugger.html](https://nodejs.org/api/debugger.html)

> Node.js's debugger client is not a full-featured debugger, but simple step
> and inspection are possible.

~~~
sigil
Thanks. I use the REPL debugger often, glad to see it's not going away.

------
STRML
This is a big release. Async/await in stable core is something I've been
(literally) waiting 6 years for.

Many people have criticized Node's cooperative multithreading model, with both
good and uninformed reasons. Yet, it is without dispute that the model is
popular.

Async/await is a giant leap forward toward making Node usable for beginner and
expert alike. This release is a celebration.

For those of you with existing applications looking to migrate, try `--turbo
--ignition` to emulate (most) of the V8 5.9 pipeline. Anecdotally,
microbenchmark-style code regresses slightly, real-world code improves by as
much as 2x. Exciting times.

~~~
rattray
> Anecdotally, microbenchmark-style code regresses slightly, real-world code
> improves by as much as 2x.

Curious, any hunches as to why?

~~~
STRML
Well, the optimizing pipeline has completely changed in V8 5.8 (if you use
`--turbo --ignition`) and in 5.9+. It's been simplified and most importantly,
does not deoptimize on quite so many common features (such as try/catch). More
information at [http://benediktmeurer.de/2017/03/01/v8-behind-the-scenes-
feb...](http://benediktmeurer.de/2017/03/01/v8-behind-the-scenes-february-
edition/) and some of his other articles.

In my testing it appears that TurboFan cannot optimize certain patterns as
well as Crankshaft did, but there's no reason to believe those regressions
will remain as TF evolves. Optimizing more code is much more important for
real apps.

------
Matthias247
This just motivated me to play around a little bit with JS async/await
implementation. What I found interesting is that async functions will always
return promises, even if an immediate value could be returned. Like for
example in the following function:

    
    
        async function getFromCacheOrRemote() {
          if (random()) {
            return "Got it";
          } else {
            await DoSomethingLongRunnning();
            return "Got from network";
          }
        }
    

The function will return a Promise independent of which branch is taken,
although it could return a string for the first branch. Does anybody know the
reason? From a consumer point of view it does not matter if the consumer uses
await, since await accepts both immediates and Promises. Is it because always
returning promises is more convenient for users which use Promise combinators
instead of await and less bug-prone? Or does it maybe even benefit JS runtime
optimizations if the returntype is always a Promise - even though the promise
in both cases might be of a different subtype?

For most applications it probably doesn't matter anyway. However returning and
awaiting immediate values eliminates an allocation and eventloop iteration
compared to using a Promise, which is helpful for high-performance code. This
is why C# now introduced custom awaitables and things like ValueTask<T>.

~~~
kentor
It would be weird for async functions to be synchronous wouldn't it?

Also the consumer is not required to use await with a called async function.
They can use .then on it, or pass it around to other functions that consumes
promises. Or, you could pass the async function to decorators that consume
promise returning functions. Using experimental decorator syntax:

    
    
        @debouncePromise
        async function() {
           ...
        }
    

Yes it is a trade off of performance for convenience and consistency.

Also... the right side of await will effectively be wrapped in a simple
Promise.resolve() if it is not a promise. Proof:
[http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap...](http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=env&targets=Node-8&browsers=&builtIns=false&debug=false&code=\(\(\)%20%3D%3E%20%7B%0A%20%20async%20function%20a\(\)%20%7B%0A%20%20%20%20console.log\(1\)%3B%0A%20%20%20%20await%201%3B%0A%20%20%20%20console.log\(2\)%3B%0A%20%20%7D%0A%20%20%0A%20%20async%20function%20b\(\)%20%7B%0A%20%20%20%20console.log\(3\)%3B%0A%20%20%20%20await%201%3B%0A%20%20%20%20console.log\(4\)%3B%0A%20%20%7D%0A%20%20%0A%20%20a\(\)%3B%0A%20%20b\(\)%3B%0A%7D\)\(\)%3B&experimental=false&loose=false&spec=false&playground=true)

~~~
Matthias247
Weird: Depends. I think that an async function might sometimes complete
synchronously is not weird - it can happen in many scenarios where the least
common denominator is "The function might sometimes take a long time and
therfore has to be async". Having a different return type depending on the
taken path (Value or Promise<Value>) is definitely weird and should not be
encouraged (although supported by JS). I'm therefore in favor of the decision
that an async function always returns a Promise - I just wanted to know if
anybody has more insight on how the decision was taken and if the performance
impact has been considered.

Thanks for bringing up the issue around that an await on a value will wrap it
into a promise before! That means even the following "workaround" would not
work:

    
    
        function getFromCacheOrRemote() {
          if (random()) {
            return "Got it";
          } else {
            return DoSomethingLongRunnningWhichMightUseAsyncAwaitInternally()
            .then(() => "Got from network");
          }
        }
    
        var result = await getFromCacheOrRemote();
    

Here getFromCacheOrRemote interferes correctly as type string |
Promise<string> in typescript. However if an await on the function will still
trigger a Promise creation and the await an eventloop iteration it won't buy
anything compared to the simply solution. Seems like to profit from
synchronous completions there's also some steps on the callsite needed like:

    
    
        var maybePromise = getFromCacheOrRemote();
        var result;
        if (typeof maybePromise === 'object' && maybePromise.then != null)
          result = await maybePromise;
        else
          result = maybePromise;
    

And just for clarification: I wouldn't encourage any normal application to do
this kind of things, the normal async functions should be great for them.
However for some libraries (e.g. high-performance networking libraries) these
optimizations can make sense. And e.g. the awaitable ValueTask<T> in C# was
created with exactly those scenarios in mind.

------
riccardomc
It really is a significant release: the world 'significant' is used in 7 of
the first 13 lines of the release statement.

[http://imgur.com/a/F572e](http://imgur.com/a/F572e)

------
samueloph
Cool!

It looks like somebody needs to set up the deb repository for 8.x, the
installation script[1] is there, but there's no repo[2] for the node 8.x
itself.

I also think this[3] url needs to get an update to reflect the new release.

edit-> Considering Debian Stretch will be released June 17th, it would be nice
to have a repo for this release, i mean ..node_8.x/dists/stretch/Release..
instead of only jessie and sid's.

[1][https://deb.nodesource.com/setup_8.x](https://deb.nodesource.com/setup_8.x)
[2][https://deb.nodesource.com/node_8.x/dists/jessie/Release](https://deb.nodesource.com/node_8.x/dists/jessie/Release)
[3][https://nodejs.org/en/download/package-manager/#debian-
and-u...](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-
based-linux-distributions)

~~~
mabynogy
Another way is to use "n": [https://github.com/tj/n](https://github.com/tj/n)

------
bricss
Long awaited release full of joy!

------
curiousgal
rant

I just finished cleaning my home folder out of the ~100,000 files npm created
over the past couple of months. I just build interesting Node projects I come
across to check them out and it's gotten that big. I wonder how it's like for
regular node devs.

~~~
webXL
Sane dependency management isn't free! I have some tips, though:

    
    
      # find how all node_modules on *nix under the cwd (gsort is for mac with homebrew coreutils; use `sort` otherwise)
      find . -name "node_modules" -type d -prune -exec du -sh '{}' + | gsort -hr
    
      # exclude node_modules from time machine backups
      mdfind 'kMDItemFSName == node_modules' -0 | xargs -0 tmutil addexclusion

------
cheapsteak
>node-inspect has been integrated directly into the Node.js runtime

Is node-inspect the same thing as node-inspector or something else?

~~~
jkrems
_Disclaimer: Author of `node-inspect`_

No, `node inspect` is the new command line debugger for `node --inspect` which
replaces `node debug` for `node --debug`. The name is derived from `node
--inspect` and has no relation to `node-inspector`.

~~~
nulagrithom
Thanks for your work! CLI has always been my primary method of debugging node,
and I'd hate to see it go away.

Is this pretty much identical to the old debugger?

~~~
jkrems
Yep, the same commands should still work. There's some additional commands now
for CPU/memory profiles. But that's the biggest difference - hopefully.

------
__s
Looking forward to writing unit tests for luwa. Node v8.0 should include wasm
1.0

------
k__
The promisify stuff looks rather clunky. Aren't there better options?

~~~
ryeguy
That's only needed to convert old callback style code to promise-compatible
code. Most libraries either return promises now or have an option to, so this
isn't necessary.

------
p5k
Notejs should get promise versions of its current callback-based APIs:

    
    
        const fs = require("fs");
        fs.writeFile("Hello, World", "helloworld.txt", (error)=>{
            if(error) throw error;
            console.log("done!");
        });
    

Should be:

    
    
        const fs = require("fs");
        fs.writeFilePromise("Hello, World", "helloworld.txt").then(()=>console.log("done!"),error=>console.error(error));

~~~
flavio81
It really should be:

    
    
       try{
            x = await fs.writeFilePromise("Hello, World", "helloworld.txt")
            console.log("done!")
       }
       catch(error)
       {
            console.error(error) // or console.log
       }
    

This takes advantage of promises fully.

