Node v8.0.0 Released
nodejs.org
nodejs.org
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. ;-)The biggest additions here with regard to async/await is the new promisify util and the async_hooks.
Edit: Changed wording and included more detail.
Edit: originally wrote 'unstable'. Meant 'non-LTS'
The improvement on the 8.0.0 version is that such an "oldie" function can be Promisified. A great improvement.
e.g. function myCallback (err, result) {...}[0]: https://medium.com/@styfle/promises-in-node-js-8-x-core-d6a8...
https://stackoverflow.com/questions/44260289/using-native-es...
awaitAll
to replace await Promise.all
calls. 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 const log = console.log.bind(console),
query = document.querySelector.bind(document),
queryAll = document.querySelectorAll.bind(document); await all([fn1, fn2]) ;)
i wonder when we will get s-expressions for function calls (awaitAll [fn1, fn2])https://github.com/nextorigin/riemann-query-parser/blob/mast...
const [foo, bar, baz] = await returnerOfPromiseCollection();
That would assume there was either a) a catch in that collect or b) some error checking, but still...The code is awaiting an array, which is already "resolved" and its returned right away. Its contents are not relevant to `await`.
Yes, once you have a promise you have to deal with it as such through the whole chain.
Also, many times you want to limit the concurrency of your promise execution which isn't something you can do with an array of promises. You'd be back to using `await` + something like https://www.npmjs.com/package/promise.map.
I'm someone that used to use `co` where you could go:
const [a, b] = yield [promiseA(), promiseB()]
But I prefer the simplicity and consistency of having to use something like Promise.all or require('promise.map').You have a point with concurrency, but handling concurrency is an another beast altogether.
How does one get to the point where they want to await multiple promises, yet they need to be insulated from the very presence of the `Promise` object?
I prefer something like p-settle most of the time https://github.com/sindresorhus/p-settle
const awaitAll = (futures) => futures.map(f => await f);
edit: this is wrong but I can't delete it. Haven't used async as much as promises.2) A request can fail and can timeout.
3) Writing to a file can fail.
And you get the idea. Don't omit error handling. Error handling is business logic too.
Being relaxed around error handling is the recipe for cascading server failure.
You should see the destructive effects of bad examples there.
You will eventually prove yourself wrong, since deemphasizing error handling goes wrong very quickly.
You don't have enough information to be outraged at the toy example.
But in this case encapsulation is a leaky abstraction that just makes the diagnosing of an error more cumbersome.
Then they added unhandled rejection warnings by default, and all was ok again - but I see why someone might insist that all examples have error handling.
.catch(error => {
process.nextTick(() => { throw error; });
})That means error handling may not be necessary inside that function. Errors are caught automatically and returned to the caller as rejected promise! You need error handling at the top level but not necessarily inside each function.
I don't think that's required. Superagent already returns promises.
https://visionmedia.github.io/superagent/#promise-and-genera...
Alas too late to edit comment.
const util = require('util'),
fs = require('fs'),
writeFile = util.promisify(fs.writeFile),
request = require('superagent'),
stat = util.promisify(fs.stat),
sorts = require('sorts'),
log = console.log;
const getPhotosAndSaveThem = async function(){
try {
const response = await request.get('https://jsonplaceholder.typicode.com/photos');
const photos = response.body.sort(sorts.byKey('title'))
await writeFile('photos.json', JSON.stringify(photos, null, 2))
const status = await stat('photos.json');
log(`I got some data from an API and saved the responses at ${status.birthtime}`)
} catch (e) {
log(`Oh no, something went wrong!`, e)
}
}
getPhotosAndSaveThem()I was wondering how this would be handled. I guess old habits die hard since this article title includes the "v".
Other relevant posts digging into new features include http://codingsans.com/blog/node-8 and https://blog.risingstack.com/important-features-fixes-node-j...
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.
somePromise.then(function() {
return a.b.c.d();
}).catch(TypeError, ReferenceError, function(e) {
//Will end up here on programmer error
}).catch(NetworkError, TimeoutError, function(e) {
//Will end up here on expected everyday network errors
}).catch(function(e) {
//Catch any unexpected errors
});
It's super useful. Sometimes you want to catch two different sorts of exception. You could do something like
f = expr `catch` \ (ex :: ArithException) -> handleArith ex
`catch` \ (ex :: IOException) -> handleIO ex
However, there are a couple of problems with this approach. The first is that having two exception handlers is
inefficient. However, the more serious issue is that the second exception handler will catch exceptions in the
first, e.g. in the example above, if handleArith throws an IOException then the second exception handler will
catch it.
Instead, we provide a function catches, which would be used thus:
f = expr `catches` [Handler (\ex :: ArithException -> handleArith ex),
Handler (\ex :: IOException -> handleIO ex)] .catch(ArithException, IOException, handleError)
Edit: Nevermind, I think what you want to be able to do is provide two different error handlers, but essentially catch them at the same time so that if you throw inside one of them, the second one wouldn't catch it.As a matter of fact, does anyone have a benchmark of the new nodejs 8's promise implementation against bluebird, because I so far bluebird was faster than the native implementation.
The benchmark was designed for realistic use in a node environment, where most of the libraries come callback based. Because of that a very fast "promisify" is really important. Native promises don't provide one so the naive implementation using standards-compatible API is quite slow.
Bluebird's promisify is a lot faster since it relies on non-standard (as in non-ES6-standard) internals instead of using the promise constructor as an ES6-based promisifier would need to do.
edit: on second thought, I haven't looked at the included `util.promisify` - it could be taking advantage of non-public internal V8 promise APIs.
[0]: https://medium.com/@styfle/promises-in-node-js-8-x-core-d6a8...
function logAppendResult( err ) {
if (err) console.err('Failed to update file');
else console.log('Successfully updated file');
}
function logWriteResult( err ) {
if (err) console.err('Failed to create file');
else console.log('Successfully created file');
}
function handleFile( filename, fileExists ) {
const timestamp = new Date().toISOString();
( fileExists )
? fs.appendFile( filename, `Updated file on ${timestamp}\n`, logAppendResult )
: fs.writeFile( filename, `Created file on ${timestamp}\n`, logWriteResult );
}
function main() {
const filename = './example.txt';
exists( filename, (fileExists) => handleFile(filename, fileExists) );
}You've repeated the if(err) check in three places.
None of your error handling bubbles up so the handlers (i.e. Logging to console.error) are buried in the individual functions.
You've pretended to avoid nested callbacks by inlining them using arrow functions.
For your sake I hope that was sarcastic.
Inlining with arrows is just a more functional approach, as I would write in Coffee:
exists filename, (fileExists) -> handleFile filename, fileExists
Anything wrong with that line of code?I just try very hard to keep my code as simple as possible.
I hope you know it's trivial to write a log function that accepts different callees so you end up with only 1 'if (err)'.
I didn't test, but I wouldn't be surprised if my example runs times faster as well btw.
[0]: https://github.com/nextorigin/el-borracho/blob/master/src/re...
P.S. Iced3 compiles to ES6 await so all of this has been working together for quite a while.
And if you replace the if(err) lines with a log(...) function it doesn't reduce them to one place. It makes you repeat the log(...) function everywhere. And you'd still need the if statement to handle the control flow.
Simple code is great, but not handling errors doesn't cut it for non throwaway applications.
We can refactor another round:
function logFsResult( type, err ){
var msg= '';
switch ( type ) {
case 'append': msg= ( err ) ? 'Failed to update file' : 'Successfully updated file';
break;
case 'write': msg= ( err ) ? 'Failed to write file' : 'Successfully created file';
break;
default: msg= 'logFsResult error, missing or invalid first argument: '+ (type || '')
}
( err ) ? console.err( msg ) : console.log( msg );
}
function handleFile( filename, fileExists ) {
const timestamp = new Date().toISOString();
( fileExists )
? fs.appendFile( filename, `Updated file on ${timestamp}\n`, logFsResult.bind(null, 'append') )
: fs.writeFile( filename, `Created file on ${timestamp}\n`, logFsResult.bind(null, 'write') );
}For example you could do something like this (sorry, don't have time to open my IDE to try the code i'm going to write):
logFsResult = (type, err) => {
map_action = {
"append": {
True: "Succesfully updated file.",
False: "Failed to update file."
},
"write": {
True: "Successfuly created file.",
False: "Failed to write file."
}
}
message = map_action[type][(err != null)] // obtain the message
method = (err)? console.err : console.log // choose logger
method(err) //invoke the correct logger with the message
}
This is an easier-to-mantain code. It separates the messages to use, from the logic. It allows you to easily configure/change the messages to log, and the method (function) for logging the error, without having to touch the decision logic. On your original example, the logic of the code was mingled with the error messages.You could say this example was more "idiomatic" ES2016.
That's a trap, I should rather make my code as readable, scalable and bug free as possible regardless of ESxxx.
I can refactor in 10 other ways (different styles) coming to the same result, but that's not what my point was about. Using promises and so is just taste or preference, if you like it you use can it, if not do without. I've seen amazing spaghetti with promises and callbacks as well.
Easy to nitpick btw:
you compare err != null?? besides not using strict mode, what should err be? a String? So, what will happen if err is undefined or an empty String?
Then you call logFsResult with err while it is not used.. Did you even consider what happens if the value of type is not available in map_action? I'll be the end of the feast!
last one: True and False as an object key are not Booleans, so if you have your IDE up and running, the code will fail.
Now, you can try to solve this with promises, just as you can try brush your teeth with a broomstick.
YOU are the one who made that comparison, not me. You originally wrote the following line:
( err ) ? console.err( msg ) : console.log( msg );
What do you think the "?" operator does with "err"?> Then you call logFsResult with err while it is not used..
It seems you don't understand the code. I'm not calling "logFsResult", i am defining a function called logFsResult. You also did the same, you defined logFsResult to receive the "err" parameter.
function logFsResult( type, err ){
var msg= '';
switch ( type ) {
> That's a trap, I should rather make my code as readable, scalable and bug free as possible regardless of ESxxx.ES6 allows you to write more readable code than ES5. Take a look at the features.
if (err) console.err('Failed to create file');
Congratulations, you're writing Go in JavaScript! :)Well, who are we to deprive you from the joy of writing lots of boilerplate code?
The real value for promises is async/await.
(There are lots of other reasons to use the promise abstraction – having a type that can be transformed is extremely useful and natural – but that one’s pretty significant.)
Using `try`/`catch` with `async`/`await` is a bit awkward, though, which is especially unfortunate because it's the #1 place you should be handling errors.
LightScript has a language feature[0] that makes it less awkward (sort of an`Either`/`Result` type) that I'm thinking about submitting to TC39.
You never need use use async / await.
> 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.
If you started programming with Node, it's like you've learned doing everything the wrong way.
The async/await brings back the sane, synchronous, reasoning. There's a reason that from Lisp to Haskell, every language tried to get rid of the error-prone callback spaghetti.
A sync await is an argument for people like you, who are trying hard to change its nature. It was added to the specs, because of "browsers got stuck to JavaScript".
There are better server side languages, so you can use them.
You can hardly escape from imperative code except without syntactic sugar either. That doesn't mean that one should program in the lower layer of abstraction of a platform. If we followed that, C programming would be all gotos instead of functions and the usual control flow (even "if" and "for" are syntactic sugar on top of assembly constructs).
>A sync await is an argument for people like you, who are trying hard to change its nature.
If it wasn't for people who tried hard to change its nature, JS would still be the same ho-hum language it was its first 15 years (I was there). Node.js was itself an attempt to "change" the nature of JS, moving it from client to server side.
The need for callbacks stems from the fact that JS as a language was never specifically event oriented -- any more than in any other language. It just supported DOM events in the browser environment, which for the first 10-15 years of the web were just simple one level callback handler (button clicked, do that). Hardly any kind of asynchronous programming to write home about. Aside from having first class functions, JS was not particularly designed for evented code. That's where callbacks came in, as a poor man's way to deal with evented code -- other languages have had coroutines, promises etc for 30+ years.
const promisify = (fn, ctx) => (...args) =>
new Promise((resolve, reject) =>
fn.apply(ctx, [ ...args,
(err, data) => err ? reject(err) : resolve(data)
])
)[1]: https://nodejs.org/api/util.html#util_util_promisify_origina...
[2]: https://github.com/nodejs/node/blob/ef16319effe396622666268c...
Having a stdlib function makes for an easy "let's just use this everywhere" answer.
I get the usefulness for arrays and object declarations. Particular to have cleaner diffs. But why for function calls?
Exactly the same reason :)
const fn = ( { arg1 = '', arg2 = [], arg3 = true } = {} ) => { }
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.
As a matter of fact, what I don't recommend is Sails [1], which tries to do as much as it can and is quite inflexible in terms of technical decisions
That said, Express will be around for quite some time, due to its name-recognition and large install base.
> 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?
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://nodejs.org/api/debugger.html
> Node.js's debugger client is not a full-featured debugger, but simple step and inspection are possible.
It's explained there. Basically, `node debug` will still work, they just had to change the command line debugger to support the new protocol, since the old protocol was removed from V8.
But unless you really need to debug from the command line, --inspect/--inspect-brk is the way to go. You don't necessarily have to use Chrome either, these days IDE debuggers support this protocol as well.
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.
Curious, any hunches as to why?
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.
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>.
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...
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.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 [2]https://deb.nodesource.com/node_8.x/dists/jessie/Release [3]https://nodejs.org/en/download/package-manager/#debian-and-u...
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.
- no bigger than 50 lines of code - probably "unpromified" - probably unmaintained
I really like ECMAScript2016 and the concept behind Node.js, but the NPM ecosystem is really something that isn't pretty.
I mean Maven's repository is usually pretty big too. It's usually compiled .jars but IDE's can opt to download sources + documentation too. A lot of Java applications end up downloading half the internet too.
Long story short, any non-trivial development / library / framework / software has a lot of dependencies.
# 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 addexclusionIs node-inspect the same thing as node-inspector or something else?
1. node --inspect app.js 2. In chrome do `about:inspect`
you now have debugger attached. WIN!
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`.
Is this pretty much identical to the old debugger?
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));Callbacks are lightest-weight re: CPU & memory overhead, so it was decided that core APIs should implement that, and developers can override using promisify (via e.g. Bluebird or the new `util.promisify()`) as they need. But putting that kind of assumption in core could lead to significant pain.
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.