Miroslav Bajtoš
Lead Node.js Engineer @ IBM
(me in 2016/2017)
(me in 2018)
async
and await
are awesome!
async & await
Source: Mozilla web docs
async function checkStatus(){
const response = await request('http://example.com/');
return response.statusCode === 200;
}
callback style
function checkStatus(callback){
request('http://example.com/', (error, callback) => {
if (error) return callback(error);
callback(null, response.statusCode === 200);
});
}
consume promises
function sleep(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
}
await sleep(100);
produce promises
async function respondToQuestion() {
await sleep(500); // (think)
return 'my answer';
}
respondToQuestion()
.then(result => console.log(result));
callbacks
function step(cb) { process.nextTick(cb); }
function walk(cb) {
return step(err => {
cb(new Error('too tired'));
});
}
Error: too tired
at step (callback.js:5:8)
at process._tickCallback (next_tick.js:61:11)
promises
function step() { return Promise.resolve(); }
function walk() {
return step().then(() => {
throw new Error('too tired');
});
}
Error: too tired
at step.then (promise.js:5:11)
at process._tickCallback (next_tick.js:68:7)
async & await
async function step() {}
async function walk() {
await step();
throw new Error('too tired');
}
Error: too tired
at walk (async.js:5:9)
at process._tickCallback (next_tick.js:68:7)
F10 steps over await statements
coming soon to Node.js 11.x
$ node --async-stack-traces index.js
https://v8.dev/blog/fast-async#improved-developer-experience
January 2017 | ES2017 |
February 2017 | Node.js 7.6.0 |
October 2017 | Node.js 8.9.0 LTS |
(see nodejs/node#15413)
util.promisify()
experimental API
require('fs').promises
require('dns').promises
https://github.com/strongloop-forks/bluebird/tree/async/await
const util = require('util');
const fs = require('fs');
const readFile = util.promisify(fs.readFile);
async function readData() {
return await readFile('data.txt', 'utf-8');
}
const http = require('http');
const pEvent = require('p-event');
async function start(handler) {
const server = http.createServer(handler);
server.listen(0);
await pEvent(server, 'listen');
return `http://localhost:${server.address().port}/`;
}
start(/*handler*/).then(
url => console.log('Listening on:', url),
err => console.log('Cannot start the server:', err)
);
async functions in callback-based code
Can you spot two problems?
async function step() {
return 'some data';
}
app.use((req, res, next) => {
step()
.then(next)
.catch(next);
});
the right way™
app.use((req, res, next) => {
step()
.then(
// onFulfilled
success => next(),
// onRejected
next
)
.catch(
// crash if callback throws
err => process.nextTick(() => { throw err; })
});
});
await
executes tasks serially
const walkResult = await walk();
const talkResult = await talk();
use Promise.all()
to run in parallel
const [walkResult, talkResult] = await Promise.all([
walk(),
talk(),
]);
const sources = [
'http://example.com',
'http://nodesummit.com'
];
// download all URLs
const result = source.map(
async (url) => await request(url)
);
// result is an array of promises!
const actualResult = await Promise.all(result);
unhandled errors (callbacks)
function tick(callback) {
throw new TypeError('undefined is not a function');
}
tick(console.log);
process crashes
unhandled errors (async)
async function tick() {
throw new TypeError('undefined is not a function');
}
// missing await or then
tick();
logs a warning, does not crash (yet)
user-land Promise libraries
How to detect unhandled rejections?
const Bluebird = require('bluebird');
async function run() {
return Bluebird.resolve(1);
}
const result = run();
console.log(result instanceof Bluebird)
// false
console.log('spread' in result);
// false
async function getRepos() {
const url = 'https://api.github.com/users/bajtos/repos';
// GOOD: return the promise immediately
return request(url);
// NOT RECOMMENDED: await the result before returning
return await request(url);
}
avoid promise rewrapping
Complete rewrite is almost never
the right thing to do.
Keep delivering value to your clients.
Work incrementally.
Focus on areas that changes most often.
Use your test suite to drive the priorities.
async functions are ready to use
learn the new programming model
(and its caveats)
upgrade your code base incrementally
Miroslav Bajtoš
(slides: bajtos.net/T)