Hacker News new | past | comments | ask | show | jobs | submit login
Node v7.5.0 Released (github.com)
281 points by nikolay on Feb 3, 2017 | hide | past | web | favorite | 136 comments



Just wanted to leave a comment about the ChangeLog which is a list of commits. It would be nice if they sat down for a day (or two) to write down proper release notes that made reference to various commits and outlined exactly what is changing, like if there are backwards compatibility issues or if there are very important bugs solved.

The changelog here looks like a git log :/ I mean, I can do better on my own projects (and have been trying to do so with node-oauth-libre) but for a major project it would be nicer if it had nice release notes.


I actually like these release notes? The commits are an extra, and messages are always clearly worded, in my humble opinion.

I guess the commit list is the first thing that pops out when skimming, but it's less important than the notable changes.

'Notable changes' is more akin to the release notes I think you want.

As for breaking changes, Node.js follows semver. A major version lists breaking changes more clearly.


...even if they only did this for the top 20/50/100 changes, it would be well worth it.


There is a lot to like about Node. I had a look a couple of years ago but lack of a definitive library to handle callback hell put me off. How is the situation these days?


You have a number of ways of keeping a handle on async code now.

1. Native ES6 promises will cover most of your basic needs. See https://developer.mozilla.org/en/docs/Web/JavaScript/Referen.... In fact, unless you have very specific needs not covered by native promises, you shouldn't drop a third party library into your project.

2. For more advanced operations on promises, use Bluebird. See http://bluebirdjs.com and http://bluebirdjs.com/docs/api-reference.html. It has a ton of features built on top of native ES6 promises. If you're using an older version of Node, it also acts as a polyfill. It can also make it easy to work with libraries that only expose a callback-based interface. So yeah, Bluebird is the shit.

3. co is a generator-based control flow library that can make your async code look more like synchronous code. It's pretty cool, but I haven't personally used it in a project, nor do I know of anyone else who uses it. It builds on top of promises and generators, and isn't very hard to understand under the hood. See https://github.com/tj/co. I wouldn't recommend it, but it might be something to play with because ...

4. ... async/await is coming to JavaScript! At a very high level, this pair of keywords is syntax sugar for what co already does as a library. This is the final stage in the evolution of taming callback hell in JavaScript, and it builds on top of everything that has come before (promises and generators). Here's a tutorial: https://blog.risingstack.com/async-await-node-js-7-nightly/


Also highly recommend the npm async library[1] even though the hipster way is now native async/wait or promises. caolan/async has some amazing sugar on nearly every use-case the most common for me being async.auto().

[1] https://github.com/caolan/async


I highly recommend against using that library - it encourages a lot of callback hell we've found at my company, and it is much harder to create nice reusable functions with it vs. promises. bluebird is a wholly superior library for handling async flow.


> it encourages a lot of callback hell we've found at my company

This is a very odd comment. async provides the same level of indentation as Promises does:

  async.waterfall([
    function(){},
    function(){},
  ])
Here's promises doing the same thing:

  function()
  .then(function(){})
  .then(function(){})
One's a list of functions to be run in order, the other uses method chaining. You may prefer one or the other but saying async 'encourages callback hell' is about as logical as saying promises does.

__Edit__: further to my own comment. The people I know who know their stuff (ie, work on JS itself) and like/prefer Promises do so because they believe that functions should return values.

I don't think anything will be better than either solution until async/await gains wide support. Async/await needs return values, so hence promises, so it's definitely worth knowing promises. But yeah, right now async is fine.


Promises also work better with Typescript, since it's well defined which type each step returns and which the next function expects. That means the .then(a => next(a)) cascades can be typechecked well. async.waterfall doesn't seem to be typecheckable.


The huuge difference once you understand its implications is that you can:

    return function().then(() => ...).then(() => ...)
...and the caller of you function can decide to chain even more stuff after, in the simplest case. Most obvious benefits, though not the biggest, is that you simply can return a promise ad drop the ugly extra callback argument that you function needs to have. For example:

    function foo(cb) {
        async.waterfall([
            function(){},
            function(){},
        ])
    }
becomes:

    function foo2() {
        return function()
            .then(function(){})
            .then(function(){});
    }
...and this way the logic ends up where it should be, in the caller, not the callee!

Another simple to explain benefits are the fact that you can .then() a promise 10 times and what it does will only happen once, and then the other times you'll just consume the result. You don't need to care if something is (a) already computed, (b) in the process of being computed, (c) scheduled for computation later etc., you can write the exact same code for all cases. Because you're working with values that have dependencies between this, not with processes that need to happen in a certain order.

The bigger benefits show up when you write more and more code and you see how beautifully it all untangles with promises.

And the fact that once you learn promises you can carry further the knwledge to other async patterns like co and async/await (they are all understandable in terms of promises).

Do yourself and everyone you work with a favor and move away from async please, especially in a team promises make everything so much easier to understand! Same advice of you're writing nodejs libraries: have you functions return promises instead of take callbacks! Drop the intellectual lazyness and grow beyond "async by callbacks", it's the worst coding style ever. And everyone will be able to convert almost instantly from promises to async/await since the logic is similar, just syntactic sugar comes over it.


As I said: promises return values. That's great. But describing callbacks as "worst coding style ever" and "intellectual lazyness" is hyperbole to describe a style that most of the JS community uses.

Also: not sure if you mean 'you' singular or 'you' plural, but personally I use a combination of callbacks for node stuff with basic async patterns applied (not the 'async' module) and promises.


The hyperbole is not my style actually, but I use it when talking about JS because I've came to realize the in the JS community it's the only way to be heard.

Generally I see the JS async styles continuum as: (0) callbacks < (1) async module < (2) promises < (3) co < (4) real async/await when language supports it, and I advocate skipping the intermediate steps in this continuum, (1) and (3) because they can lead to either badly composable code or subtle bugs. Also, I stressed the "intellectual lazyness" label because I know lots of people learn async module and this, "ok, this is good enough, I'll stop learning new things about writing better async code in JS".

...and I'm ok with good ol' callbacks where it makes sense for performance reasons, like core part of web frameworks or game engines (even if there is no sensible speed reduction, there is a memory overhead from creating a zillion promises).


It also provides more specific control flow functions that are bug-prone to roll your own with promises. I've learned a lot by looking at the source!


Yea but when using promises with async/await its very beautiful.

    await asyncFuncOne();
    await asyncFuncTwo();
No more weird water-falling, and finally proper exception handling. The only gotcha is the fact that we cant awaits at the root of a module, and we need to wrap it in a async function.


The 250Kb extra weight to the Babel bundles (compared to the equivalent callback version) is quite frustrating though.


I use Node a lot, and I find myself reaching for the async library any time the project reaches a non-trivial size and there's a lot of communication going on between services. I don't find it all that hard to read (the async.waterfall method looks somewhat like promises chaining) I suppose I should spend a weekend or two steeping myself in promises and es7. It's mildly annoying to have to learn a new async paradigm every couple years, and like others have pointed out, the Node core hasn't changed - its still callbacks.


So much of the promise-based code I see looks almost the same as it would with plain callbacks, just with the callbacks plopped into .then(). Am I missing something? How do promises make for more reusable functions?


In my opinion, these are the major ones:

1. Promises are a value. They can be passed to other functions. This simplifies a lot of control flow.

2. The `.then` method on a promise is similar to `flatMap` in other languages / libs. The next chain will wait for any nested promises to complete. This flattens callbacks so you can see the flow instead of the pyramid of doom.

3. Native promises include a bit of sugar, such as Promise.all. You need a library to do this with callbacks.

4. Promises are the backbone of async/await. You need them to use it.

Example:

    await const [a, b] = Promise.all([getA(), getB()]);


5. Error handling and even successful termination is very, very easy to get wrong with nested callbacks (forgetting to call a callback, or forgetting to catch unexpected exceptions and pass them to the callback, means the function never returns at best or brings down the whole process at worst). Promises make this much easier by automatically propagating errors for you down the promise chain (though you or your caller do still need to handle the error at the end of the chain).


Nit, but await is an operator, not an annotation on a statement. So that should be written as:

    const [a, b] = await Promise.all([getA(), getB()]);


I'm surprised no one has mentioned my favorite aspect of Promise, which is the fact that you can plop a .catch at the end of a chain and it will do the error handling there regardless of where in the chain it failed. Doing this with long chains of asynchronous calls before Promise was a huge pain in the ass.


Chaining and returning can keep things nice and neat. Say you are following a Controller -> Service -> Repo implementation.

Controller calls the service.

Service returns a call to a repo with any mapping that needs to occur.

Repo calls out to database or external api and returns the promise.

Makes the work very boring and repetitive for the most part which is a good thing I think.

    function someController(req, res) {
        UserService.getUser(req.session.user)
            .then(SomeService.getSomething)
            .then((val) => res.json(val))
            .catch(handleError);
    }

    function getSomething(user) {
        return SomeRepo.getSomething(user)
            .then(MapSomething)
            .catch(alternativeHigherLevelCatch);
    }

    function getSomething(user) {
        return new Promise((resolve, reject) => {
            database.getSomething(
                'defined parameters',
                user,
                resolve,
                reject
            )
        });
    }


It's trivial to refactor that code to use only callbacks, without ending up with callback hell.

You certainly want to call UserService.getUser for many different controllers. Why manually do that for each controller? Simply make a middleware to get the user.

If you take this to its logical conclusion, you end up with small, composable middleware functions, and controllers that are pure functions.


Well sure with a single service and a single mapper etc. Once you start tacking on multiple it keeps following the pattern above with promises and just extends with `.then`'s.

Also agree middleware is a good solution which can go through and provide a user object directly onto the request or another level of abstraction created if you prefer. That was simply to show how multiple service calls could be easily tied together rather than a full and usable example.

A benefit of callbacks though, at least from my experience, is error messages when testing with mocha / chai. I only have experience with jasmine, mocha, and chai but the errors when test driving were much easier to follow with callbacks.


Because promises are chainable, it can take N level-deep code down to 1 level deep. So that's your first big win.

The second one is that you can await a promise, which turns your 1-level-deep code to 0 levels deep.


I wouldn't necessarily say they make for more reusable functions. I think primarily their purpose is to provide a cleaner abstraction for dealing with async code flow. Plus I just love seeing code like:

doSomething.then(stepTwo).then(stepThree).catch(errHandler);


I should have added that I'm asking to compare the special parts (e.g. reduce, waterfall, etc) of Bluebird vs the async library.


You can take the part before `.then()` and pass it around.


yes that works quite great. you have to define a 'async' function, in which you can use the 'await' keyword.

async getDoc(doc) {

  const result = await db.get(doc)

  console.log('result:', result)
}

// instead of:

function getDoc(doc) {

  db.get(doc, result => {
    console.log('result:', result)
  });
}

// or

function getDoc(doc) {

  db.get(doc)
    .then(result => 'result: ' + result)
    .then(::console.log)
    .catch(::console.error)

}


The "hipster" way? Do they wear a silly hat and have little-to-no pant break?


IMO promises and Bluebird made `async` obsolete.


They certainly did not, if for nothing other than `async.auto()`, which automatically runs a dependency graph of async functions.


A Promise/async/await implementation of 'async.auto' is trivial, as you can use the behavior of promises themselves to avoid solving the graph:

  async function Promise_auto(tasks) {
      const keys = Object.keys(tasks);
      const results = { };
      const taskPromises = { };
      function runTask(key) {
          if (!taskPromises[key]) {
              taskPromises[key] = (async () => {
                  let fn = tasks[key];
                  if (fn instanceof Array) {
                      const deps = fn.slice(0, -1);
                      fn = fn.slice(-1)[0];
                      await Promise.all(deps.map(runTask));
                  }
                  results[key] = await fn(results);
              })();
          }
          return taskPromises[key];
      }
      await Promise.all(keys.map(runTask));
      return results;
  }
Usage example (terms intentionally out of order):

  (async () => {
      const start = new Date();
      const results = await Promise_auto({
          write_file: ['get_data', 'make_folder', async (results) => {
              console.log('in write_file', results);
              await Promise.delay(1000);
              return 'filename';
          }],
          email_link: ['write_file', async (results) => {
              console.log('in email_link', results);
              await Promise.delay(1000);
              return {file: results.write_file, email: 'user@example.com'};
          }],
          get_data: async () => {
              console.log('in get_data');
              await Promise.delay(1000);
              return [ 'data', 'converted to array' ];
          },
          make_folder: async () => {
              console.log('in make_folder');
              await Promise.delay(900);
              return 'folder';
          },
      });
      console.log('results = ', results);
      console.log(`It took ${(new Date() - start) / 1000} seconds`);
  })();


Here is a complex dependency graphs built with no nesting and no "special" methods, only a combination of `then` and `all`

  function test(name1, name2) {
    let user1 = User.find(name1)
    let user2 = User.find(name2)
    let post1 = user1.then(u => Posts.getLast(u.id))
    let post2 = user2.then(u => Posts.getLast(u.id))
    let comparison = Promise.all([post1, post2])
      .then(([p1, p2]) => DiffService.compare(p1, p2))
    let email1 = Promise.all([user1, comparison])
      .then(([u1, c]) => Email.send(comparison.text(), u1.email))
    let email2 = Promise.all([user2, comparison])
      .then(([u2, c]) => Email.send(comparison.text() ,u2.email))
    return Promise.all([email1, email2])
  }


I am confused. Your recommendations 1 and 2 seem to conflict with one another. I use Bluebird now for promisification, and I also used a few other features including the resource management (disposers). Does this mean that I will be using Bluebird and not native promises for the foreseeable future? Or can/should I use Bluebird with native promises? (Or would that just make things slower if it is even possible?)


Automatic promisification and the disposer pattern are both Bluebird-specific features that native ES6 promises don't support, so you'll have to continue using Bluebird if you rely on them.

However, promises returned by Promises/A+ compliant libraries -- and this includes native ES6 promises -- are interoperable with each other. That means you can mix Bluebird promises with native promises for the most part. E.g, passing an ES6 promise to Bluebird's Promise.all will work just fine. This works up to a point, and breaks when you try to use a Bluebird-specific function that's expecting additional functionality to be attached to the promise object.

I don't see why mixing Bluebird promises with ES6 promises would make anything slower. You shouldn't worry about this.


Native promises and bluebird use different microtask queues on Node which makes interop incorrect (which is also one of the reasons why bluebird is ES6 spec non compliant). See https://gist.github.com/anonymous/9936c695f2c29e79a0c1a0dec8...

This might lead to subtle ordering bugs, I would recommend against using both together.

Using bluebird and native promises together may result in slower performance because V8 has fast paths for native promises which fail for bluebird.


If the ordering is important, then you should be using

    a()
    .then(()=>b())
    .then(()=>c())
Assuming anything about the completion order of:

    a():
    b();
    c();
Where a, b and c are async tasks of any kind (be they classic old callbacks, Promises, Observables, whatever) is just asking for trouble. The whole point is that you don't care about when it finishes, you just want to know that it has finished. If the order is that important and you don't want to handle managing it, you should just write standard synchronous code.


In what way is this incorrect? Those are three separate promises; no code can be correct that depends on whether one resolve() call finishes before an independently started resolve() call, right?


Bluebird is faster than native promises as well.

http://softwareengineering.stackexchange.com/questions/27877...


I've used the `co` library at work to extensively trim down and simplify a lot of server-side Node.js code recently. It's worked out very well compared to the very Promise heavy code we had before, especially since so many database libraries now make use of promises. I would highly recommend it if you're going to be stuck using Node v6 for the next 2-4 years.

On the front-end, we're using TypeScript 2.1.5, so we've been able to make good use of async/await there. The only tricky parts are dealing with AngularJS, due to the way it handles change detection via scope digests.

Both solutions still require the use and understanding of ES6 promises, especially when dealing with code that only works with callbacks.


Promises don't cover a lot of scenarios in async usage. When building some node apps, especially toolage, doing everything async just isn't possible, or is a lot more work for little benefit. The second you use a promise, anywhere, working with its output is now also async, you cannot 'wait' for it. I don't know if async/await actually does this or not, but until that functionality exists in JS, working with node, for me, is a pile of junk code, especially when libraries force you to use them asynchronously.


>working with its output is now also async, you cannot 'wait' for it ... , but until that functionality exists in JS, working with node, for me, is a pile of junk code, especially when libraries force you to use them asynchronously

Asynchronicity is something that Node makes explicit and necessary for I/O, and it's practically a core principle of Node and javascript. If you try to avoid asynchronicity entirely, then you're not going to get much further than you would if you tried to avoid classes in Java.

Async/await is a very useful syntax sugar to working with promises, but it's not built to let you ignore asynchronicity entirely.


My understanding was that Node didn't support native ES6, is that no longer the case? Or are you talking about using a transpiler?


Node has supported all of ES6 except modules since 6.0.


Ah, this explains it. I tried to use an import statement a couple days ago and it failed, so I assumed it still wasn't supporting ES6. Good to know!


Node supports all of ES2015 and ES2016 and will soon support ES2017 in the next few months or so.

So yeah, for most things you don't need to use a transpiler.


A year or two ago that was the case. Then io.js forked, implemented a bunch of features and later was brought back into the NodeJS fold. Since then, Node has been a lot more proactive about keeping up with newer specs.


You can always check here: http://node.green


I don't see ES6 modules (import/export keywords etc) in that list. Where is that feature hiding?


The loader spec hasn't been completed yet so there is no way to load properly modules in es2015, es2016, or es2017 as far as I know.


But the syntax is in es2015. So that feature should be marked as NO in those tables.


Grandparent: "lack of a definitive library"

Parent: "You have a number of ways"

Do you see the irony?


We've been using async/await (transpiled with babel) for last one year in our production API code. There really is not any need to use those async control flow libraries anymore.


I've found that this works fine until you have a bug in your async function that is, after transformation, a promise and a generator away from your original function with no call stack available for debugging.

Edit: My experience is with babel's generator version of async/await, so other transformations may be easier to work with.


Agree, except we use TypeScript as the transpiler. Async/Await down to es5. Works like a dream.


The Koa web framework built by the guys behind Express is pretty neat. You can do stack like calls with it, rather than callbacks, via generator functions.

Not sure what the uptake is like but you can find more at http://koajs.com.


Latest version has replaced generators with async/await.


Good to know! I have an app running on it but haven't touched it in a while.


Have they fixed the middleware graveyard? When I last used it, I found it insanely difficult to pick the correct middlewares due to the changes between versions.


That won't get better until koa 2.x drops the @next flag (when async/await lands in node).

But I've never run into an issue that was "insanely difficult".


> lack of a definitive library to handle callback hell put me off.

1) Promises.

2) Caolan's async is wonderful for handling all sorts of 'async' problems, like async map and stuff. As close as a de facto library as you can get.


The standard library is still callback hell and the async package doesn't use promises at all.


Promises have been native in node for awhile, so any time you spend in callback hell is entirely your prerogative.


Wrapping every standard library method with my own promises sounds like just another flavour of hell, and it still doesn't address the fact that the standard library is callback hell.


Callback hell isn't the characteristic of having a callback-based API. It's the code you get when you try to compose it and conditionally fork it without any better abstractions.

So promisifying a callback-based API does address it by either letting you use a yield/await abstraction or at the very least promise composition.

Wrapping a callback-based API is such a mechanical process that you can wrap entire modules at a time, so I'm not sure what's hellish about that when it gives you promises, something you can actually work with.


I agree with you but FWIW there are both big (Bluebird) and small (pinky-promise) packages to promisify stuff.


promise-ring is one library that does the wrapping automatically from node-style callbacks to promises. I think Bluebird also has an auto-wrapper.


These days you can use: Promises, generators and even async/await.


Whole standard api is still using callbacks so you would need to write your wrappers around it to not use callbacks.. And async/await is not solving anything because your definitions of fuctions will still need callbacks/promises under the hood anyway (unless you use libraries that do it for you). I like how Go solves that, gorutines and you write your code as it would be normal sync code.


    > And async/await is not solving anything because 
    > your definitions of fuctions will still need 
    > callbacks/promises under the hood anyway
The point is that you can write your complex business logic with async/await which is easier to follow and get right. I mainly use it in my routers and database modules.

It doesn't need to factor out every .then() or callback from your codebase to be incredibly useful or to fulfill its purpose.


I imagine the likes of Babel currently hide all of this in the Node context, but is there a move to either change the standard API to async/await, or provide a standard mirror API?

Either option sounds full of compatibility / maintainability headaches, so how does Node get from its current state of callback hell out the box to async / await?

goroutines aren't magically turning async calls into sync, just hiding them deeper "under the hood"; there must be hope for Node.


> is there a move to either change the standard API to async/await

From what I remember there was no plans to change that (based on discussion from couple of months ago by node members on github).

> Either option sounds full of compatibility / maintainability headaches

It is.

> goroutines aren't magically turning async calls into sync, just hiding them deeper "under the hood"; there must be hope for Node.

Of course it's not about turning code into sync one, it's about coding style to look like it would be a sync one. But in case of Go it was created with this as main language concept, everything was designed around it, scheduling, user space lightweight stacks for gorutines etc.


There is a V8 API to expose Promises directly from native modules, and that can eventually be used to make async functions first-class citizens.

async functions using promises and generators under the hood is a good thing because it allows easy usage between the two forms.


This still doesn't solve what I wrote about api, libuv (event loop + IO) that node.js use is also based on callbacks in C, last time i checked discussion about it, there was no plans to change that.


That simply won't change, because that's what node.js (and Javascript) is fundamentally about: An EventLoop, with callbacks that are used to handle events. All the promises and async/await are only sugar around callbacks, so they don't change the fundamental model.

A Go like model, with lightweight or real threads and no need for callbacks or promises will also need new synchronization mechnanisms in order to handle preemption and waiting which are currently not in scope of javascript, e.g. mutexes, condition variables, etc.


For the few std lib calls that I make in web apps, I just use Bluebird to promisify() node style callbacks into promise style code, always worked fine for me.


There is also a Reactive Extensions implementation available to handle async stuff.

So if you know these from another language, RxJS is worth a try :)


Tried with node.js for a few months and now back to php7/lavarel, node.js eco-system still evolves quickly and I need a stable backend right now, so far php7 works well for me and seems the development is faster.


Async/await is a really wonderful addition to JavaScript !


Someone already mentioned about the co library. My personal experience is that it is excellent and massively simplifies async calls. The API resembles the async/await pattern: you use the keyword "yield" instead of "await". Async calls look as if they are sync. The code that includes heavy use of async methods such as in a database application greatly benefits from co in terms of code readability.


The async library has been a definitive resource for years.


Many people are complaining that the standard library still uses callbacks and so even though you have async/await, you can't use it with the standard library.

I wholeheartedly agree. I don't understand why someone hasn't build a compat library that simply promisifies all the standard library (it isn't that big), taking the edge cases into account.


Because the standard library doesn't really have that many callback based functions.

The more important issue here is that Promises are seen as fundamentally incompatible with post-mortem debugging due to their empty-the-stack requirement: https://promisesaplus.com/#point-34

If the stack is emptied when handling an exception, the context in which that exception happened is completely lost, so its not clear how to get the process to dump a core that contains meaningful information regarding the problem.

This is whats currently blocking node from fully switching to promises. Apparently many companies that have influence in node core rely heavily on post-mortem debugging and don't find the situation acceptable.


Both Q and bluebird promises optionally support long stack traces, albeit at a performance hit. And in practice even old style callbacks often (usually?) empty the stack.


No, old style callbacks don't empty the stack on thrown errors - they crash.

Long stack traces are fine, but post-mortem debugging means analyzing the entire program's core dump. That includes everything that was in the heap at the time, and not just the names of the functions on the stack but also their arguments (which often point to stuff in the heap). It can be used to reproduce most of the program state at the time of the crash.

The real problem is that at some point node decided that throw = programmer errors = core dump. This is wrong and misguided, but thats another story...


From my experience majority of async functions that I used are from the fs package and for that, there is nice wrapper called fs-promise (1) which converts all the functions from callbacks to promises.

For other stuff, I just create my own promise wrapper (if I feel like that promise interface would be better), which is like 5 lines of code.

[1] https://www.npmjs.com/package/fs-promise


There are like 10 of those, fwiw.



There are multiple that do that. `mz` is the most popular I know of.


This is probably not the answer you're looking for, but you could look into ways that make callbacks enjoyable. The syntactic sugar provided by CoffeeScript goes a long way to make readable (and, dare I say, elegant) what would be a tangled mess in straight up JavaScript:

  # Get profiles LIST as JSON
  .post "/list", (req, res) ->
    db.maria.query getProfilesQuery, { userId: req.session.passport.user }, false
      .on "result", (result) ->
        rows = []
        res.status(200)
        result
          .on "row", (row) -> rows.push row
          .on "error", (error) -> logger.warn error
          .on "end", -> 
            res.json rows
            res.end()
5 callbacks here but they don't impede readability.


Maybe it's just me, but this would look infinitely more readable to me if I could tell where each callback starts and where it ends, i.e. in plain JavaScript.


What impedes readability here is that you don't simply have an async function `getProfiles({ userId })` that gives you a list of profiles, either taking a callback or returning a promise.

A lot of that is pointless noise. You don't need to set the status code to 200 or call end(). `res.json(profiles)` will do.

And these days, Coffeescript is just Javascript with some optional parens. Can't think of many upsides in 2017 to not just using ES6.



Add --harmony flag to enable stable ES7 features (or transpile with Babel) and use async/await, it's marvellous.


Node 8.0.0 has it enabled without --harmony. Will be a great release to upgrade to.


Node 8 has not been released.


That's why I said "will be"


TypeScript async/await helps a lot with this. Type safety plus async ops. Awesomeness.


I feel like it should be clarified here that async/await is not exclusive to TypeScript, but a ES7 (?) feature that is also available if you use the Babel transpiler.

Having type safety is great of course, but it might be too heavy to add if you just want good async handling.


You may add types at a later time while enjoying the rest of the features.


RxJs (or equivalent FRP streams library) handles this perfectly.


http://callbackhell.com/

I think the mental gymnastics needed to write non blocking code also makes you understand the flow of your program, witch allows good abstractions. After a while it becomes a second nature and you get a mental picture of all branches.

Thinking about code as events (button.onclick = showPicture), makes you a better programmer, as this is how a computer work. And when your program has to scale across several CPU's or servers, it will come naturally to you.

Multi threaded solutions can be easier at first, but when you need to have threads that communicate, and handle locks etc, that too becomes hard.


Yes! Callback hell is a gift that forces you to refactor code until it's easy to understand and your abstractions are correct.

Promises are a band-aid that gives you shallower indentation, and then simply hides the callback complexity in invisible objects that are even harder to debug.

The problem is the modern web development world is all about creating two classes of programmer: framework programmers who control their entire stack, and application programmers who suckle at the teat and can't modify libraries, only writing composite works out of building blocks.

Application programmers only feel safe when they have an exhaustive palette of libraries that they can use, because they know they can't modify anything. They thrive on feeling taken care of.

Framework programmers only feel good about themselves when they know they're working on something so complicated that application programmers will never be able to understand it. They enjoy creating an simple interface for the common man, while solving "hard problems" in abstract domains. They thrive on superiority.

This creates an impermeable layer that can never be refactored (framework programmers don't have access to app code, app programmers can't modify the frameworks). So when someone encounters callback hell, the necessary refactoring to find the right interfaces is impossible.

Promises work well in this dead layer, because they create a clear boundary of responsibility between these two kinds of programmers. But the cost is thousands of tiny invisible state machines, with no labels or semantics.


    > Callback hell is a gift that forces you to
    > refactor code until it's easy to understand
That doesn't sound like a gift to me. Unless you meant they are so painful as an abstraction that they gifted us with promises and then async/await.

Almost everyone here has worked with callbacks and you'll be hard-pressed to find people that felt like they improved the code base.

Just tiny changes to the logic, like an if-statement with branching async behavior, would cause disproportionally large changes in the callback structure, pretty much touching every line/indentation.

The rest of your post is really negative and judgmental. Not sure why you felt it was necessary.


Oh, sorry... in editing I forgot the bit about where promises fit in the framework/app paradigm. Added a paragraph.


refactoring is better then an extra if and argument. and force you to understand the code and result in less bugs.


> Use system CAs instead of using bundled ones

Does this make the npmrc config for cafile redundant now in my MITM environment? The amount of projects that just can't handle the CA or worse, a proxy setting, is very irritating.

Will we not have to make a separate config for every app that also bundles node (e.g. vscode) or anything that uses node to get a file (vue-cli, node-pre-gyp, etc)?


I recently left a job that has a proxy. I would estimate the my time spent there working on proxy related issues to be more than 2 months over the 5 years I was there. Is it too unreasonable to evaluate the cost of these proxies beyond the maintenance cost?


You can specify your own CA store or revert to the OpenSSL one with `--use-openssl-ca`, `SSL_CERT_DIR` and `SSL_CERT_FILE`. See: https://github.com/nodejs/node/blob/master/doc/api/cli.md#--...

The PR is pretty good: https://github.com/nodejs/node/pull/8334/files


It's a shame the v8 5.5 backport (https://github.com/nodejs/node/pull/11029) didn't make it in but it looks like it won't be long.


Yep, should be soon, it's already going into 7.5.1 test builds https://github.com/nodejs/node/pull/11062#issuecomment-27658... Instructions are there on how to install the test build it with nvm, so you can start using it already :)


Can't wait... need me some async await without babel.


In 7.2.x, you could do async await with just a --harmony flag.


I might be mistaken but I believe there were some major performance issues with the older async/await implementation.



Yes, on the other hand, if you are like me and use them for one-off scripts, they are great.


I don't keep up with node end ES version compliance but is there a scheduled release that'll target all ES6 features?


I don't think so. They try as hard as possible. A lot of it is directly related to V8. In Node.JS v8.0.0 nightly they currently support 70% of the ES2015 spec without flags.

You can check the progress here: http://node.green/


According to the site:

Node.js ES2015 Support is at 99% for v8.0.0 nightly.

Node.js ES2017 Support is at 74% for v8.0.0 nightly.


Oh right I totally missed that the header changes as you scroll !


Wow, me neither. The discoverability there is pretty poor... if the header was just augmented with a dropdown, that would be great :)


Strictly speaking, tail call optimization is an ES6 feature. I had the impression that its implementation in V8 is on hold, so it might be a while.


AWS Lambda is so far behind......


I don't understand


"AWS Lambda supports the following runtime versions: Node.js – v4.3.2"

http://docs.aws.amazon.com/lambda/latest/dg/current-supporte...


Technically you can use the latest version of Nodejs in lambda by bundling the binary with your lambda package and use the handler script to run the binary. The binary need to be compatible with Amazon Linux though, so you'll probably need to compile the binary on an ec2 instance running Amazon Linux.


To be fair, 4.3.2 the current LTS version, but would ideally be migrated prior to April.

https://github.com/nodejs/LTS


Isn't node v6 the current LTS version? I think each even major version is LTS, and 6 is the latest one of those.


There is an overlap. Both V4 and V6 are currently LTS until April.


v6 is indeed LTS.


Better than the Python story, at least ...


Yeah! Sadly, if you wanna do actual Python (3.x?) stuff on aws you're better off rolling your own or paying premium to "have it all solved" on heroku :((


I pay $16/month for Heroku. Is AWS really that much cheaper?


By far. I use lambda as a public API for my sites. One site has 4000req / h (at peeks. Not much, but it's an api after all) and I only pay some cents.


Are there plans to add coroutines support ?




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: