Node v7.5.0 Released
github.com
github.com
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 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.
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/
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.
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.
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.
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).
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.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()]); const [a, b] = await Promise.all([getA(), getB()]);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
)
});
}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.
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.
The second one is that you can await a promise, which turns your 1-level-deep code to 0 levels deep.
doSomething.then(stepTwo).then(stepThree).catch(errHandler);
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)
} 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`);
})(); 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])
}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.
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.
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.http://softwareengineering.stackexchange.com/questions/27877...
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.
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.
So yeah, for most things you don't need to use a transpiler.
Parent: "You have a number of ways"
Do you see the irony?
Edit: My experience is with babel's generator version of async/await, so other transformations may be easier to work with.
Not sure what the uptake is like but you can find more at http://koajs.com.
But I've never run into an issue that was "insanely difficult".
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.
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.
> 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.
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.
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.
async functions using promises and generators under the hood is a good thing because it allows easy usage between the two forms.
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.
So if you know these from another language, RxJS is worth a try :)
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.
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.
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...
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.
# 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.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.
Having type safety is great of course, but it might be too heavy to add if you just want good async handling.
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.
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.
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)?
The PR is pretty good: https://github.com/nodejs/node/pull/8334/files
You can check the progress here: http://node.green/
Node.js ES2015 Support is at 99% for v8.0.0 nightly.
Node.js ES2017 Support is at 74% for v8.0.0 nightly.
http://docs.aws.amazon.com/lambda/latest/dg/current-supporte...