Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MunichJS - What awaits you in async programming?

MunichJS - What awaits you in async programming?

This presentation guides you through the world of asynchronous programming in JavaScript, more specifically the async/await paradigm. First, we'll compare async/await to other similarly-purposed paradigms. We'll then cover current browser support and performance implications of async/await, as well as a recent optimization done in V8 and how this affects the everyday work of web developers. We’ll finish with advice on how every JavaScript developer can get involved with standardization efforts and as a result help to shape the future of the language.

Maya Lekova

October 10, 2018
Tweet

More Decks by Maya Lekova

Other Decks in Programming

Transcript

  1. > whoami • Maya Lekova • Background in game development

    ⇨ mainly in C++ • Working in the V8 team in Google ⇨ mainly in C++, JavaScript, CSA • Benedikt Meurer • JavaScript developer (sort of) • V8… what?
  2. What are we going to talk about today? The four

    “How’s”: 1. How do we do async in JavaScript? 2. How fast and well-supported is async? 3. How do I debug asynchronous code? 4. How can I get involved?
  3. HTTP request handler Read user’s avatar fs.readFileSync Query DB for

    user’s data db.getUserData GET /user_profile send HTTP response Assemble data and avatar
  4. “An asynchronous model allows multiple things to happen at the

    same time. When you start an action, your program continues to run. When the action finishes, the program is informed and gets access to the result (for example, the data read from disk).” Source: “Eloquent JavaScript”, Marijn Haverbeke, 3rd edition
  5. HTTP request handler Read user’s avatar fs.readFile Assemble data and

    avatar callback GET /user_profile send HTTP response Query DB for user’s data db.getUserData callback Event loop running
  6. Pros • Faster handling of the request • Doesn’t block

    the main event loop • Easier to implement uniform error handling • Scales better! ⇨ Allows for better throughput • Harder to write • Harder to read & debug ⇨ Needs more attention & education Cons
  7. Callbacks const server = http.createServer(function(req, res) { // … authenticate

    user, attach userId to req fs.readFile(req.userId + '_avatar.png', function(err, avatar) { api.compressUserData(avatar, function(err, data) { res.end(data, function(err) { // … clean-up after response is sent }); }); }); });
  8. Preparation const util = require('util'); const fs = require('fs'); const

    api = require('my-library'); const http = require('http'); const readFile = util.promisify(fs.readFile); const compressUserData = util.promisify(api.compressUserData); const sendResponse = util.promisify(http.ServerResponse.prototype.end); // Promisify all the things!
  9. Promises const server = http.createServer((req, res) => { // …

    authenticate user, attach userId to req readFile(req.userId + '_avatar.png') .then(api.compressUserData) .then(sendResponse.bind(res)) .then(() => { // … clean-up after response is sent }) .catch((err) => { // … clean-up after response is sent }); });
  10. Async to the rescue! async function foo() { await some_promisified_function();

    // do_more_things await other_async_function(); }
  11. Async/await const server = http.createServer(async (req, res) => { //

    … authenticate user, attach userId to req const avatar = await readFile(req.userId + '_avatar.png'); const data = await compressUserData(avatar); await sendResponse.call(res, data); // … clean-up after response is sent });
  12. Error handling const server = http.createServer(async (req, res) => {

    try { const avatar = await readFile('nonexistent.png'); const data = await compressUserData(avatar); await sendResponse.call(res, data); } catch (err) { sendResponse.call(res, JSON.stringify(err)); } finally { // … clean-up after response is sent } });
  13. Support • Browsers: latest Chrome, Firefox, Edge, Safari - 100%

    • Servers: Node.js 8+ - 100% • Transpilers: Babel 6+ Source: http://kangax.github.io/compat-table/es2016plus/#test-async_functions
  14. Recent optimization in V8 • Promise/async micro-benchmarks: https://github.com/v8/promise-performance-tests • Speculatively

    change behaviour • Propose a PR to the language specification https://tc39.github.io/ecma262/#await - current spec https://github.com/tc39/ecma262/pull/1250 - the pull request • … and now we (a)wait!
  15. await Promise.resolve(undefined) Promise Fulfilled undefined Promise Pending N/A PromiseResolveThenableJob Promise

    Pending N/A main PromiseReactionJob PromiseReaction Resume main [[Resolve]] v p t
  16. await Promise.resolve(undefined) Promise Fulfilled undefined Promise Fulfilled undefined PromiseResolveThenableJob Promise

    Pending N/A main PromiseReactionJob PromiseReactionJob Resume main [[Resolve]] v p t
  17. await Promise.resolve(undefined) Promise Fulfilled undefined Promise Fulfilled undefined PromiseResolveThenableJob Promise

    Fulfilled undefined main PromiseReactionJob PromiseReactionJob [[Resolve]] Resume main v p t Await (original version)
  18. await Promise.resolve(undefined) Promise Fulfilled undefined Promise Fulfilled undefined PromiseResolveThenableJob Promise

    Fulfilled undefined main PromiseReactionJob PromiseReactionJob [[Resolve]] Resume main v p t Await (optimized version) Removal of throwaway broke async_hooks
  19. • We optimize away 2 of the ticks (run with

    --harmony-await-optimization flag) • Doxbee - 48% improvement in time • Fibonacci-async - 23% improvement in time • Hapi real-world benchmark ◦ With Async hooks enabled - 50% improvement in throughput ◦ Without Async hooks enabled - 20% improvement in throughput ◦ Thanks to @matteocollina for the results Await (optimized version)
  20. await Promise.resolve(undefined) Promise Fulfilled undefined Promise Fulfilled undefined PromiseResolveThenableJob Promise

    Fulfilled undefined main PromiseReactionJob PromiseReactionJob [[Resolve]] Resume main v p t Await (moar optimized version) Only allocated when async_hooks or DevTools is in use (as of today!)
  21. • Don't allocate the throwaway promise ◦ except with async_hooks

    / DevTools ◦ github.com/tc39/ecma262/pull/1146 crbug.com/v8/8285 • Doxbee - another 7% improvement Await (moar optimized version)
  22. Utilize information in promise chains async function foo(x) { await

    bar(x); } async function bar(x) { await x; throw new Error(); } foo(1).catch(e => { console.log(e.stack) }); bit.ly/v8-zero-cost-async-stack-traces
  23. Limitations • Only shows await continuations (with --harmony-await-optimization), i.e. other

    promise continuations aren't visible function foo(x) { return bar(x).then(y => undefined); } (could be extended to show promise continuations as well) • Doesn't work in Node (yet)...
  24. “Ecma’s Technical Committee 39 (TC39): maintains the ECMAScript language standard

    (and more). Members of the committee are all major browser vendors and other companies interested in the web. Those companies send delegates to meetings which are also attended by invited experts.” Source: http://2ality.com/2011/06/ecmascript.html
  25. Where can I plug in? • Meetings every 2 months

    (follow at github.com/tc39/agendas) • Discuss proposals online & offline (follow & comment at github.com/tc39/proposals) • Write ECMAScript conformance tests (give a hand at github.com/tc39/test262 )