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

io.js and the future of server-side JavaScript

io.js and the future of server-side JavaScript

Slides from the talk given at YGLF 2015 (http://yglf.co).

Avatar for Benjamin Gruenbaum

Benjamin Gruenbaum

June 10, 2015

Other Decks in Technology

Transcript

  1. server side You, open source and the future of JavaScript

    Benjamin Gruenbaum - TipRanks NodeJS
  2. What io.js is io.js is a drop-in replacement for node.js

    and is compatible with nearly all the modules in npm.
  3. What io.js is io.js is a community driven open source

    project. It was started by the primary contributors to node.js but in the first few months attracted more active developers than the node.js project has had in its entire history.
  4. io.js and NodeJS Recently the io.js technical committee voted to

    merge with the NodeJS foundation. So soon - NodeJS and io.js converge
  5. let for(var i = 0; i < clients.length; i++){ client.onmessage(function(){

    // we all know this - all 10 console.log("Got message", i); }); }
  6. Maps and Sets var obj = new Foo(); var map

    = new Map(); // create a map s.set(obj, 15); // object keys, proper ownership var s = new Set(); s.set(obj); // sets contain no duplicates.
  7. WeakMaps and WeakSets var foos = new WeakMap(); function getFoo(){

    let foo = getFromLibrary(); // want to save data about foo foos.set(foo, {some: "data" }); } foos.get(f); // access external data
  8. More // template strings tag `Hello ${expression}!` // Symbols -

    Scoped and safe extensions myIterable[Symbol.iterator]; // Native promises (more on those later) getFoo(arg).then(function(val){ // no error param //throw Error("Promises are throw safe"); return val + 1; // can also return a promise });
  9. Promises Promises are an abstraction over the notion of a

    time and a value. Promises provide a Domain Specific Language for asynchronous flow control in JavaScript.
  10. Promises A promise has three possible states: - pending -

    operation has not yet completed. - fulfilled (value) - operation completed successfully. - rejected (error) - an error condition occurred Once a promise changes state it can’t change state again - If a promise is fulfilled with 1 it will forever stay that way.
  11. Promises Promises chain and are throw safe: getFoo().then(function(foo){ return getBar(foo,

    15); // return promise or value }).then(function(bar){ return getBaz(bar, 10); // can throw here, throw safe }).catch(function(err){ // like a sync try/catch // handle error across the chain in one place - no (err, res) });
  12. Promises Promises are easy to aggregate: Promise.all([getFoo(), getBar()]).then(function(results){ // both

    foo and bar are ready here. }); Promises are native: Promise > function Promise() { [native code] }
  13. The problem let jay = '{"x:5}'; Promise.resolve(jay).then(function(j){ JSON.prase(j); // typo

    (in any method) JSON.parse(j); // still throws - invalid JSON x.y.z(j); // what if no y property? // ... actual processing }).then(function(val){ // this never executes - I don't know why - no notification });
  14. The problem let jay = '{"x:5}'; Promise.resolve(jay).then(function(j){ JSON.prase(j); // typo

    (in any method) JSON.parse(j); // still throws - invalid JSON x.y.z(j); // what if no y property? // ... actual processing }).done(); // throw on rejection - not in ES2015 promises
  15. Finland I participate in the Stack Overflow JavaScript Chat. In

    2013 I flew to Finland to a month. There, I met a fellow user and chat friend Petka. Petka was very upset about the performance and debuggability of promises at the time.
  16. bluebird Bluebird is a super fast and easy to debug

    promise library. It has a rich API and everyone should use it.
  17. bluebird I’ve personally been a contributor of the project along

    with Gorgi Kosev since 2013. Version 3.0 is coming out soon with awesome improvements.
  18. So Petka wrote bluebird More importantly - bluebird had unhandled

    rejection detection. getBar().then(function(bar){ return bar * 3; }).then(function dealWithBar(barManip){ return getFoo(barManip); });
  19. So Petka wrote bluebird Unhandled rejection Error: FooFailed at getFoo

    (...) at dealWithBar (...) From previous event: at runGetBar (...)
  20. Unhandled Rejection Detection 1. If a promise is rejected and

    it has no error handlers: a. Wait for all micro tasks to finish running b. If there are still no error handlers i. report the error.
  21. Step 1 I wanted to be able to do this

    using any type of promises: // I need this to find out about unhandled rejections process.on("unhandledRejection", function(reason, p){ … }); // I need this to find out about false positives process.on("rejectionHandled", function(p){ … });
  22. Step 1 I did the relevant market research - going

    through every library in GitHub that uses bluebird’s unhandled rejection hooks.
  23. Step 1 I talked to the community immediately involving the

    relevant people. People were willing to help.
  24. Step 2 I made a short (3 page) non-formal specification

    of the intended behavior. Communication matters.
  25. Possibly Unhandled Rejection NodeJS Promise Hook Unhandled Rejection Tracking Several

    promise libraries such as bluebird and when as well as some native promise implementations offer potentially unhandled rejection tracking. This means that the following: Promise.reject(new Error("err")); // never attach a `catch` Does not get silently suppressed being an error but instead gets logged to the console or otherwise treated by the promise library. A common request is a way to handle rejection application wide. NodeJS code often includes several copies of the same promise library or different promise libraries and it is currently difficult to install a global hook on potentially unhandled rejections. For example code using Bluebird for concurrency, akamai for their API, bookshelf as an ORM and request- promise for web requests uses 4 promise libraries already - 3 Bluebirds and a WhenJS. If someone wants to log errors for
  26. for web requests uses 4 promise libraries already - 3

    Bluebirds and a WhenJS. If someone wants to log errors for all tracked unhandled rejections they'd have to add at least four handlers - if they miss any their code won't do what they expect. This document attempts to offer a standard way for promise libraries and potentially native promises in Node to communicate they have detected an unhandled rejection. The hook In order to handle rejections the following new events will be fired on process: Event 'unhandledRejection': Emitted whenever a possibly unhandled rejection is detected. This event is emitted with the following arguments: • reason the rejection reason of the promise susprected in having an unhandled rejection • p the promise suspected in having an unhandled rejection itself. process.on('unhandledRejection', function(reason, p){ console.log("Possibly Unhandled Rejection at: Promise ", p, " reason: ", reason);
  27. console.log("Possibly Unhandled Rejection at: Promise ", p, " reason: ",

    reason); // application specific logging here }); Event 'rejectionHandled': Emitted whenever a possibly unhandled rejection was mistakenly identified and was eventually handled. For example if the promise library made a mistake considering p in the following case unhandled: let p = Promise.reject(new Error("err")); setTimeout(() => p.catch(function(){}), 86400); This event is emitted with the following arguments: • p the promise who was believed to be an unhandled rejection. This event is useful in order to recover from detection mistakes. While in my experience this rarely happens in practice this additional hook helps in such cases.
  28. Backwards incompatible changes None that I am aware of. No

    one is currently firing events by these names in NodeJS code in GitHub. In other languages Promises as an abstraction are indeed not unique to JavaScript - let's explore what other languages do. • in C# 4.0 and .NET in general - such a hook exists for Task with an unterminated error handler will crash your application unless you add a TaskScheduler.UnobservedTaskException event handler. In 4.5 you can handle errors yourself (like .catch). • In Scala it used to silent fail (lots of surprised answers in SO - e.g.http://stackoverflow.com/questions/24453080/) but that upset peoplehttps://groups.google.com/forum/#!searchin/scala- user/The$20silence$20of$20failed$20futures/scala-user/1X2QISf3604/2dw0XhMh0RUJ , they now intend to support that case. • Dart futures already do this forwarding rejections to the global error handler.
  29. So overall it seems like other programming environments support a

    unhandled rejection hander. Note that JavaScript is pretty special in that it is the only case I know of where a lot of different implementations of this abstract concept exist. Statistics These are usage statistics about events current libraries already fire. These usage examples were collected from public GitHub projects using bluebird promises offering (non-global) hooks. First a summary of bluebird's onPossiblyUnhandledRejection from GitHub. Large (>1000 stars) libraries typically don't change onPossiblyUnhandledRejection, the largest ORMS: Sequelize, Waterline and Bookshelf do not hook on it however users of those libraries sometimes do. It also very common for people to override it in test code. Here are libraries and projects using onPossiblyUnhandledRejection in their code: • https://github.com/FelisCatus/SwitchyOmega (843 stars, proxy switch, custom logger) • https://github.com/AppGyver/steroids (237 stars, PhoneGap extension, throw and crash) • https://github.com/att/rcloud (153 stars, AT&T R script cloud thing, defaults to custom logging) • https://github.com/simplyianm/githubfollowers/ (101 stars, defaults to log and adds a console log, rather pointless call)
  30. • https://github.com/tyabonil/request-promise/ (50 stars, promisified package, actual custom logic) •

    https://github.com/mikermcneil/waterline2/ (20 stars, waterline ORM proposed next generation, defaults to suppress behavior) • https://github.com/PhilWaldmann/openrecord (19 stars, ORM, lets user configure, defaults to log) • https://github.com/wikimedia/restbase (14 stars, Wikipedia people, log) • https://github.com/zaggino/brackets-snippets (14 stars, overrides to crash). • https://github.com/mozilla/fxa-oauth-server (9 stars, by Mozilla, undefined passed to get Q like behavior). • https://github.com/kenspirit/kanban-cfd (8 stars, Kanban graph visualization, crash) • https://github.com/mattlewis92/angular-bluebird-promises (6 stars, bluebird for angular, passes noop (this is slighly upsetting :D)) • https://github.com/Evisions/vertebrae (5 stars, Backbone extension, custom logging) • https://github.com/mzgol/check-dependencies (6 stars, npm dependency check, suppress (TODO above)) • https://github.com/speech/speech.js (3 stars, namecoin domain thing, crash) • https://github.com/iarna/promisable (3 stars, promises module, references that it acts like throw e; not actual bluebird) • https://github.com/maseb/thicket (2 stars, framework, crash) • https://github.com/sebinsua/neo4j-promised (2 stars, custom logic to overcome heavior change)
  31. • • https://github.com/vkarpov15/wagner-core (1 star, framework, suppress (comment above "swallow

    bluebird annoying error messages")) • https://github.com/jdeanwaite/eDVR (1 star, DVR, defaults to log with default to throw commented) • https://github.com/opinsys/puavo-ticket (1 star, ticket system, custom logging) • https://github.com/wikimedia/mediawiki-services-restbase (0 stars, mirror of Wikipedia service, logging) • https://github.com/ZJONSSON/express-clues (1 star, express api wrapper, suppress) • https://github.com/AaronO/q-bluebird (0 stars, Q API Bluebird wrapper, custom logging) • https://github.com/mattlewis92/generator-nasty (0 stars, yeoman generator, defaults to log) • https://github.com/bjoerge/proxyreload (0 stars, proxy, passes null) • https://github.com/ericnorris/node-cdb (0 stars, cdb implementation, ignores) • https://github.com/shanesmith/gerrit-cli (0 stars, no diea, throws) • https://github.com/Bornholm/nap-bootstrap (0 stars, overrides to crash). • https://github.com/mcirclek/website-client (0 stars, defaults to custom logging) • https://github.com/chrisdoble/amd-to-closure (0 stars, converts AMD to closure compiler syntax, suppress) • https://github.com/colonyamerican/cah-logger (0 stars, overrides to crash) • https://github.com/micirclek/cki-portal (0 stars, site, suppress) • https://github.com/dinexcode/dnxapp-gatewayd (0 stars, unclear, log)
  32. • • https://github.com/srcspider/prototyping (0 stars, seed, defaults to crash) •

    https://github.com/martin-liu/m- sails/blob/f02f33a60c424517168b365c0c61da4ad85b8ba6/api/coffee/services/Promise.coffee(0 stars, personal project) • https://github.com/danprince/cyvasse (Game, 0 stars, undefined passed to get Q like behavior, lots (100) like this using bundler.js) Future work Add a similar solution for promise libraries in browsers, possibly the WhatWG proposal. Related work: • Promise Inspection Protocol • Bluebird's onPossiblyUnhandledRejection • WhatWG browser proposal
  33. Step 2 I contacted all libraries and authors asking them

    to consider implementing. The feedback was really good.
  34. Step 2 Some libraries I helped with. I wrote a

    pull request to the Q library which got merged in in Q 1.3.0. I had help with it from Kris and Domenic.
  35. Step 2 Some people just dropped by and left nice

    feedback: “I feel like the proposal here is the right thing to do for now.” - Paul Irish
  36. Step 2 I made issues on the joyent/node and the

    iojs/io.js (now nodejs/io.js) repositories.
  37. Step 2 I made issues on the joyent/node and the

    iojs/io.js (now nodejs/io.js) repositories. NodeJS: Consider exposing unhandled rejection hook Jan 8th
  38. Step 2 I made issues on the joyent/node and the

    iojs/io.js (now nodejs/io.js) repositories. NodeJS: Consider exposing unhandled rejection hook Jan 8th Anyone? Jan 22th
  39. Step 2 I made issues on the joyent/node and the

    iojs/io.js (now nodejs/io.js) repositories. NodeJS: Consider exposing unhandled rejection hook Jan 8th Anyone? Jan 22th Would you at least backport this from io.js? Feb 8th
  40. Step 2 I made issues on the joyent/node and the

    iojs/io.js (now nodejs/io.js) repositories. io.js: Consider exposing unhandled rejection hook Jan 8th I like this idea, what about… Jan 8th Sounds good, what should the behavior be on X? Jan 8th
  41. Step 2 I made issues on the joyent/node and the

    iojs/io.js (now nodejs/io.js) repositories. io.js: Here are some clarifications Jan 8th Nice idea, I made an attempt at a PR Jan 8th Some clarification Jan 8th
  42. Step 2 I made issues on the joyent/node and the

    iojs/io.js (now nodejs/io.js) repositories. io.js: Here are some clarifications Jan 8th Nice idea, I made an attempt at a PR Jan 8th Some clarification Jan 8th
  43. Step 3 Implement unhandled rejection tracking Implement unhandled rejection tracking

    for promises as specified in https://gist.github. com/benjamingr/0237932cee84712951a2 Fixes #256 commit a81693e964fbe3441ce34ac66fbf19cfb78620871 parent e80f803 petkaantonov authored on Feb 8
  44. The Giant Pull Reqest Issue The pull request had over

    400 messages. People helped a ton. Shout out for vkurchatkin, Domenic, rvagg, trevnorris and bnoordhuis. Lots of others too.
  45. It landed process.on('unhandledRejection', function(reason, p) { console.log("Unhandled Rejection at: Promise

    ", p, " reason: ", reason); // application specific logging and/or throwing an error. });
  46. Late sync io flag Can detect synchronous io performed late

    - super helpful to debug code. Original idea by ChALkeR for opt out flag. Opt in idea by yours truly, implemented within a week by trevnorris.
  47. `fs` improvements By thefourtheye (Sakthipriyan Vairamani) Clean up fs module,

    modernize it to use maps. Remove redundant functions. User had no prior connection or experience with io.js and made a helpful contribution.