48 comments

[ 19.9 ms ] story [ 212 ms ] thread
Node 8 is the planned LTS release for later this year.

Notably, it brings async/await syntax to vanilla JS. This new feature complements callbacks and largely replaces how Promises are currently consumed (opting for sequential-like execution with try/catch blocks instead of Promise chains).

The closest analogue would be Tasks in C#.

EDIT: removing reference to node-v8 to prevent confusion.

It's just Node 8. They stopped prefixing with "v" this version in order to avoid confusion with the V8 javascript engine.
But instead they created confusion on how to write the node version number :)
If the goal was to avoid confusion, it was an incredibly dumb decision. I'll continue referring its standard version number: Node v8.
Aync/await is the best thing since sliced bread. It has made my life so much easier.
Agreed! once you start using it there's no going back (along with `util.promisify`)
I started using Async/Await and liked it, but I've been learning more about functional programming and went back to Promises
It IS promises ;) labeling a function as async makes it return a promise. await is sugar for avoiding having to roll your own promise tree.
Sounds interesting -- do you have any resources handy that cover what you allude to (spec. comparing async calls to promises, and favoring the latter?) I use both in my ui code and they seem to have their niche for me. I prefer promise based calls when I want to separate out fetching data from the state-mutating callback, or when I may want to "cancel" something (ex: fetch a list of items for a list component, then unmount the component before the list returns -- no need to handle the response data anymore).
Unfortunately not, my opinion is simply based on my personal experience and on what I've been learning along the way. I find promises really handy for data processing pipelines (grab some data and perform some transformations over it to get it in the form you need), regardless of wether any of the steps is async or not. I still find async/await really useful and mix it with promises if I need it, but I prefer to keep my code as functional as I can. Besides, I don't really like how JavaScript handles exceptions and would rather staying away from try/catch if possible
There is no difference, async/await is just another promise notation.
Although async/await is simply syntax sugar around promises, there's a huge difference indeed. With async/await your code keeps an imperative style, while with promises code end up with a functional look
I understand the reasons why async/await is designed the way it is, but I still think it is backwards. Really if you wanted to truly make async programming approachable, you should make it transparent. What I mean by this is that instead of marking a function as async, and awaiting values, you'd mark lines as async, opting out of implicit awaits. I wrote up some thoughts on this here:

https://github.com/utilise/emitterify/issues/1#issuecomment-...

The way it is now, I defensively await things all over the place. What's worse, it propagates. If any of your function's dependencies are async, your function will also have to be async (or be ok with continuing operation after it's returned) and it turtles all the way down.

It is nicer than having to deal with promises directly though, there is that.

Agreed. Async is like a virus. Once you start somewhere pretty much everything else must be async too. In C# you can call async code from not async code and then call Task.Wait. Not sure if JS can do that.

But it still beats promises or callback hell.....

You can't really transition between async and sync scopes, no.
A better term than virus is that async is a monad. Welcome to programming with monads. ;)

JS async produces Promises like C# produces Task, so you can call an async function and use the result as a Promise.

Can you wait for a promise synchronously? I am pretty new to JS so please forgive if this is a stupid question.
It's not something JS engines allow today. It's also not something that entirely makes sense from the perspective of a browser threading model or even the libuv-based NodeJS threading model.
I know. We have some wacky use cases where it would make sense. The real answer would probably be to say "Don't use Node for this" but that's a different discussion above my pay grade.
The real answer is probably "those places you think need to synchronous don't need to be synchronous" and you need a refactor or a rearchitecture.
Trust me. We are not totally stupid. We need synchronous actions under some circumstances.
> But it still beats promises or callback hell.....

And then() hell ...

Are they still calling it 'v8' instead of 8?

Also notable is that async/await isn't new for node, 7.10 supported it (and previous versions with a flag). It's new for a LTS release. What is new, however, is the in-built util.promisify that can convert callbacks into native promises.

They dropped the "v" from the version name.

Yeah, a lot of companies won't touch non-LTS Node though, so a lot of users won't use async/await until later this year when the next LTS is released (Oct 2017).

They dropped the "v" from the version name.

Except in their official release blog posts, it seems :-D

Promises are and always were retarded. They did nothing to alleviate callback hell which was most of the point of their existence. I have no idea why they implemented them instead of async/await in the first place. Now we have to deal with mixing both for years.

Another fine example of JavaScript trying to be hip and ignoring the lessons learned from countless other languages over the years.

I see this constantly with JS like with the 3+ ways to check for NaN and the object "freeze" system that doesn't actually make objects immutable. They take a solid concept from other languages then put a snazzy spin on it that makes it fucking useless. Then try again in the next version. JS library and syntax is littered with corpses of failed experiments.

At least they finally have a usable ForEach loop after three attempts.

Please typescript save us from this hubris.

You do realize that implementing promises is a prerequisite for async/await, right?
Is it really a requirement? I would think callbacks and a preprocessor are sufficient.
Yes, it's a requirement. If you're using a preprocessor you're not supporting async, you're factoring it out.

Otherwise the argument collapses to: we don't need any of these features, we just need NAND.

You do realise that async/await is basically syntactic sugar for promises in JS, don't you?
How would you propose that async/await work without Promises? Even C#'s async/await uses the same concept: https://msdn.microsoft.com/en-us/library/system.threading.ta...

Pending the implementation of new language syntax, raw Promises were a practical solution for what they set out to accomplish. If you don't think they improved callback hell at all, I expect that you probably weren't using them correctly (an easy mistake to make without looking at the documentation and/or reading the wrong tutorials / blog posts).

cf.

    getAsyncValue1(a =>
        getAsyncValue2(a, b =>
            getAsyncValue3(b, c =>
                doSomething(c)
            )
        )
    );
and

    getAsyncValue1().then(a =>
        getAsyncValue2(a)
    ).then(b =>
        getAsyncValue3(b)
    ).then(c =>
        doSomething(c)
    );
Sure, async/await flattens that to zero nested callbacks, which is great, but with that off the table I'd rather deal with code flattened to one level deep (or a few, in some edge cases) than arbitrarily many. And that's just the "callback hell" improvement; don't forget what a nightmare error handling with callbacks can be — you have to handle both synchronous exceptions and error value callback parameters, you have to deal with the possibility of the asynchronous function unexpectedly calling your callback more than once, etc.
I upgraded a universal React/typescript project from node 6.10 to 8.1 this week. Configured typescript compilation in webpack to target es2017 server-side and es5 client-side. It worked flawlessly.

Debugging async functions (server-side) is a lot better now that there is no transpiler mangling my code beyond recognition.

Would you mind sharing your tsconfig(s)? And also do you use sourcemaps on the server?
This is my tsconfig.server.json:

   {
      "files": [],
      "compilerOptions": {
        "baseUrl": ".",
        "moduleResolution": "node",
        "target": "es2017",
        "jsx": "react",
        "experimentalDecorators": true,
        "sourceMap": true,
        "skipDefaultLibCheck": true,
        "lib": [ "es2017", "dom" ],
        "allowJs": false,
        "paths": {
          "*": [ "./ClientApp/types/*", "*" ]
        }
      },
      "exclude": [
        "bin",
        "obj",
        "node_modules"
      ]
    }
edit: remove unneeded entries
Looking at "paths", shouldn't those @types (history, redux & react) be picked up automatically, at least as of TypeScript 2.0?

Also:

  "*": [ "./ClientApp/types/*", "*" ]
I like that. I may have to add it to my app and get rid of our typings.d.ts (currently included through "files") once and for all.
They were there to fix "Duplicate identifier" errors caused by multiple dependencies fetching their own copies of type definitions.

But you are right: typescript or those dependencies have improved and they are no longer necessary. I removed them and everything still works.

Now's as good a time as any to ask:

What tools do you folks use to monitor your node dependencies and make sure you are keeping everything up to date?

npm outdated -l
But in addition to that, how do you "update all and bump relevant package.json entries, dependencies _and_ devDependencies as appropriate" ?

`npm update --save` or `npm update --save-dev` say explicitly "save updates to `dependencies` resp. `devDependencies`", which causes duplication between dependencies and devDependencies. (Say you have a dep foo and a devDep bar and both are outdated: `npm update --save` will bork package.json with an additional incorrect dep bar, and `npm update --save-dev` will bork it with an additional incorrect devDep foo :-/ )

Am I missing something? I understand there are 3rd-party packages providing such functionality, but is there any reason to not cover this feature in npm?

I use npm-check-updates[1] which will update the package.json file with the latest versions of each dependency.

[1] https://www.npmjs.com/package/npm-check-updates

Yeah that's the package I meant with "3rd-party packages providing such functionality", thanks for pointing it out :) ! Was wondering if there was a reason other than "because no one developed it" for such a feature not being in npm core.
I just regularly run `yarn upgrade-interactive` in my projects.

I was thinking of making dependency-updates part of the CI-pipeline, using a 'allow_failure'-flag. However, if you decide not to upgrade a dep for some reason, this will cause each and every build to throw a warning.

https://www.npmjs.com/package/npm-check-updates is a small command line utility that will report which dependencies are out of date, and can also upgrade your package.json from the CLI while maintaining your existing semantic versioning policies and ranges across an upgrade (instead of just bumping for every minor update).

Mostly I just really like the compact output, and the short "ncu" command which I run every day to check what's available :)

Definitely something to the addage "if it ain't broke don't fix it". Some of our less critical modules are set to latest others are updated with care. Our modules are not under source control so are refreshed on deployment. We use Snyk to monitor for vulnerabilities, works pretty well.
Are you at least checking in your npm-shrinkwrap.json? (If not you've got pain waiting to happen, that you won't find out about until deploy time)!
This so much - shrinkwrap before it bites you when a CI kicks off a deploy that fails because it pulled latest minor dep release that broke everything (happened even in big lib like Angular 2 for us after stable 2.2 !) while your local box is running fine with a cached older version.
Yes. I've had an app break due to a dependency's dependency update. Was the night before a big product launch. Learned to rely on npm-shrinkwrap the hard way.