Slide 1

Slide 1 text

ES7 and Beyond! Jeremy Fairbank jeremyfairbank.com @elpapapollo

Slide 2

Slide 2 text

Hi, I’m Jeremy jfairbank @elpapapollo blog.jeremyfairbank.com

Slide 3

Slide 3 text

We help brands excel. simplybuilt.com Your website, SimplyBuilt. pushagency.io

Slide 4

Slide 4 text

ES7

Slide 5

Slide 5 text

ES2016 ES.next ES.later ES.whatisgoingon? ES7

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Many proposed features, several coming after ES7.

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Transpiler • Convert ES6/ES7/ES.later code into equivalent ES5 code. • Babel • babeljs.io

Slide 11

Slide 11 text

TC39 Process • Five stage process for converting an idea to a standard feature. • https://tc39.github.io/process- document

Slide 12

Slide 12 text

Stage 0 - Strawman • Informal idea or proposal for change or addition. • Function bind operator 
 • Do expressions foo::bar(); let y = do { let x = 40; x + 2; }

Slide 13

Slide 13 text

Stage 1 - Proposal • Make a case for addition by describing use cases, challenges, high-level API. • Class and property decorators class Foo { @memoize bar() { return 42; } }

Slide 14

Slide 14 text

Stage 2 - Draft • Precise syntax and semantics; initial spec. • Object rest and spread properties let obj = { ...otherObj, x: 'foo' };

Slide 15

Slide 15 text

Stage 3 - Candidate • Completed spec; needs reviewing for refinements. • SIMD - Single instruction, multiple data • Exponentiation operator
 • Array.prototype.includes
 3 ** 2; // 9 [1, 2, 3].includes(2); // true

Slide 16

Slide 16 text

Stage 3 - Candidate • Async Functions
 async function loadOrders() { const orders = await fetchJson('/orders'); console.log(orders); }

Slide 17

Slide 17 text

Stage 4 - Finished • Ready to be included in the next ES standard. • No proposals at Stage 4 at the moment.

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Slide 20

Slide 20 text

Class Decorators • Annotate and modify classes and their properties. • Use @ and an expression that evaluates to a function. • Decorator precedes a class or method definition. • github.com/wycats/javascript-decorators

Slide 21

Slide 21 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get fullName() { return `${this.firstName} ${this.lastName}`; } } const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank

Slide 22

Slide 22 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get fullName() { return `${this.firstName} ${this.lastName}`; } } const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank Getters are nonenumerable by default.

Slide 23

Slide 23 text

Solution?

Slide 24

Slide 24 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } } Object.defineProperty(Person.prototype, 'fullName', { enumerable: true, get() { return `${this.firstName} ${this.lastName}`; } }); const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank // fullName: Jeremy Fairbank

Slide 25

Slide 25 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } } Object.defineProperty(Person.prototype, 'fullName', { enumerable: true, get() { return `${this.firstName} ${this.lastName}`; } }); const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank // fullName: Jeremy Fairbank

Slide 26

Slide 26 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } } Object.defineProperty(Person.prototype, 'fullName', { enumerable: true, get() { return `${this.firstName} ${this.lastName}`; } }); const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank // fullName: Jeremy Fairbank

Slide 27

Slide 27 text

More complex and less declarative.

Slide 28

Slide 28 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } @enumerable get fullName() { return `${this.firstName} ${this.lastName}`; } } const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank // fullName: Jeremy Fairbank

Slide 29

Slide 29 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } @enumerable get fullName() { return `${this.firstName} ${this.lastName}`; } } const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank // fullName: Jeremy Fairbank

Slide 30

Slide 30 text

class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } @enumerable get fullName() { return `${this.firstName} ${this.lastName}`; } } const p = new Person('Jeremy', 'Fairbank'); for (const key in p) { console.log(`${key}: ${p[key]}`); } // firstName: Jeremy // lastName: Fairbank // fullName: Jeremy Fairbank

Slide 31

Slide 31 text

How do decorators work?

Slide 32

Slide 32 text

function enumerable(target, name, descriptor) { descriptor.enumerable = true; return descriptor; }

Slide 33

Slide 33 text

function enumerable(target, name, descriptor) { descriptor.enumerable = true; return descriptor; } Object being modified (e.g. prototype or a class based on usage)

Slide 34

Slide 34 text

function enumerable(target, name, descriptor) { descriptor.enumerable = true; return descriptor; } Name of property that will be added to target

Slide 35

Slide 35 text

function enumerable(target, name, descriptor) { descriptor.enumerable = true; return descriptor; } Object literal defining the property that will be added to target

Slide 36

Slide 36 text

function enumerable(target, name, descriptor) { descriptor.enumerable = true; return descriptor; } Optional if you mutate descriptor. Useful if you want to create new descriptor.

Slide 37

Slide 37 text

Transpiling @enumerable get fullName() { return `${this.firstName} ${this.lastName}`; } let descriptor = { get() { return `${this.firstName} ${this.lastName}`; }, enumerable: false, configurable: true }; descriptor = enumerable(Person.prototype, 'fullName', descriptor) || descriptor; Object.defineProperty(Person.prototype, 'fullName', descriptor);

Slide 38

Slide 38 text

Decorators can take arguments too.

Slide 39

Slide 39 text

class Person { constructor(name) { this.name = name; } @alias('sayHello') greet() { console.log(`Hello. My name is ${this.name}.`); } } const person = new Person('Jeremy'); person.greet(); // Hello. My name is Jeremy. person.sayHello(); // Hello. My name is Jeremy.

Slide 40

Slide 40 text

function alias(aliasName) { return (target, name, descriptor) => { const newDescriptor = Object.assign({}, descriptor, { value(...args) { return this[name](...args); } }); Object.defineProperty( target, aliasName, newDescriptor ); }; }

Slide 41

Slide 41 text

What about decorated classes?

Slide 42

Slide 42 text

const Quadrupedal = { walk() { console.log(`${this.name} walks with four legs`); } }; @mixin(Quadrupedal, EventEmitter.prototype) class Dog { constructor(name, age) { this.name = name; this.age = age; } haveBirthday() { this.age++; this.emit('birthday', this); } }

Slide 43

Slide 43 text

const Quadrupedal = { walk() { console.log(`${this.name} walks with four legs`); } }; @mixin(Quadrupedal, EventEmitter.prototype) class Dog { constructor(name, age) { this.name = name; this.age = age; } haveBirthday() { this.age++; this.emit('birthday', this); } }

Slide 44

Slide 44 text

const dog = new Dog('Tucker', 8); dog.on('birthday', d => { console.log(`${d.name} just turned ${d.age}`); }); dog.haveBirthday(); // Tucker just turned 9 dog.walk(); // Tucker walks with four legs

Slide 45

Slide 45 text

const dog = new Dog('Tucker', 8); dog.on('birthday', d => { console.log(`${d.name} just turned ${d.age}`); }); dog.haveBirthday(); // Tucker just turned 9 dog.walk(); // Tucker walks with four legs From EventEmitter From Quadrupedal

Slide 46

Slide 46 text

Why Class Decorators? • Extremely powerful and expressive syntax for class/property modification. • Mixins — avoid fragile base class or multiple inheritance issues. • @autobind, @deprecate, @memoize, @readonly, and more! • github.com/jayphelps/core-decorators.js

Slide 47

Slide 47 text

Slide 48

Slide 48 text

Object Rest and Spread • Gives objects rest and spread capabilities like arrays in ES6. • Use ... operator. • Rest operation is like pick function in lodash or a clone function. • Spread operation is like syntactical sugar for Object.assign. • github.com/sebmarkbage/ecmascript-rest-spread

Slide 49

Slide 49 text

Rest - Destructuring import isEqual from 'lodash/lang/isEqual'; const assert = ::console.assert; const obj = { a: 42, b: 'foo', c: 5, d: 'bar' }; const { a, b, ...rest } = obj; assert(a === 42); assert(b === 'foo'); assert(isEqual(rest, { c: 5, d: 'bar' }));

Slide 50

Slide 50 text

Rest - Destructuring import isEqual from 'lodash/lang/isEqual'; const assert = ::console.assert; const obj = { a: 42, b: 'foo', c: 5, d: 'bar' }; const { a, b, ...rest } = obj; assert(a === 42); assert(b === 'foo'); assert(isEqual(rest, { c: 5, d: 'bar' }));

Slide 51

Slide 51 text

Spread const obj = { x: 42, y: 100 }; const newObj = { z: 5, ...obj }; const otherObj = { ...obj, x: 13 }; assert(isEqual(newObj, { x: 42, y: 100, z: 5 })); assert(isEqual(otherObj, { x: 13, y: 100 }));

Slide 52

Slide 52 text

const obj = { x: 42, y: 100 }; const newObj = { z: 5, ...obj }; const otherObj = { ...obj, x: 13 }; assert(isEqual(newObj, { x: 42, y: 100, z: 5 })); assert(isEqual(otherObj, { x: 13, y: 100 })); Spread

Slide 53

Slide 53 text

const obj = { x: 42, y: 100 }; const newObj = { z: 5, ...obj }; const otherObj = { ...obj, x: 13 }; assert(isEqual(newObj, { x: 42, y: 100, z: 5 })); assert(isEqual(otherObj, { x: 13, y: 100 })); Spread

Slide 54

Slide 54 text

const obj = { x: 42, y: 100 }; const newObj = { z: 5, ...obj }; const otherObj = { ...obj, x: 13 }; assert(isEqual(newObj, { x: 42, y: 100, z: 5 })); assert(isEqual(otherObj, { x: 13, y: 100 })); Spread

Slide 55

Slide 55 text

Transpiling Spread const newObj = { z: 5, ...obj }; const newObj = Object.assign({ z: 5 }, obj); const otherObj = { ...obj, x: 13 }; const otherObj = Object.assign({}, obj, { x: 13 } );

Slide 56

Slide 56 text

Usage: Default Options function createDog(options) { const defaults = { breed: 'Sheltie', name: 'Tucker' }; return { ...defaults, ...options }; }

Slide 57

Slide 57 text

Usage: Default Options createDog(); // { breed: 'Sheltie', name: 'Tucker' } createDog({ breed: 'Golden Retriever', name: 'Shadow' }); createDog({ name: 'Chance' }); // { breed: 'Sheltie', name: 'Chance' }

Slide 58

Slide 58 text

Usage: Redux const INITIAL_CONTACT = { name: '', email: '' }; function reducer(state = INITIAL_CONTACT, action) { switch(action.type) { case 'UPDATE_NAME': return { ...state, name: action.payload }; case 'UPDATE_EMAIL': return { ...state, email: action.payload }; default: return state; } }

Slide 59

Slide 59 text

Why Object Rest/Spread? • Succinct syntax instead of Object.assign calls. • Pick/omit object properties. • Clone objects. (WARNING: Not a deep clone.) • Provide overridable default options in a function.

Slide 60

Slide 60 text

Slide 61

Slide 61 text

And the moment you’ve been awaiting.

Slide 62

Slide 62 text

Async Functions • Provide synchronous-like syntax for asynchronous code. • Prepend function with async. • Use await operator on a promise to obtain a fulfilled promise value. • github.com/tc39/ecmascript-asyncawait

Slide 63

Slide 63 text

function fetchCustomerNameForOrder(orderId, done, fail) { fetchOrder(orderId, function(err, order) { if (err) { logError(err); fail(err); } else { fetchCustomer( order.customerId, function(err, customer) { if (err) { logError(err); fail(err); } else { done(customer.name); } } ) } }) }

Slide 64

Slide 64 text

function fetchCustomerNameForOrder(orderId) { return fetchOrder(orderId) .then(order => fetchCustomer(order.customerId)) .then(customer => customer.name) .catch(err => { logError(err); throw err; }); }

Slide 65

Slide 65 text

Workarounds.

Slide 66

Slide 66 text

async function fetchCustomerNameForOrder(orderId) { let order, customer; try { order = await fetchOrder(orderId); } catch(err) { logError(err); throw err; } try { customer = await fetchCustomer(order.customerId); return customer.name; } catch(err) { logError(err); throw err; } }

Slide 67

Slide 67 text

Asynchronous code with synchronous-like syntax.

Slide 68

Slide 68 text

async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1);

Slide 69

Slide 69 text

async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1); Declare a function as async

Slide 70

Slide 70 text

async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1); Await a promise and obtain the fulfilled/ resolved value. Nonblocking.

Slide 71

Slide 71 text

async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1); x x

Slide 72

Slide 72 text

How do async functions work at a high level?

Slide 73

Slide 73 text

async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1);

Slide 74

Slide 74 text

Invoke function. async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1);

Slide 75

Slide 75 text

async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1); Encounter await.

Slide 76

Slide 76 text

async function printOrder(orderId) { const order = await fetchOrder(orderId); console.log(order); } printOrder(1); Wrap awaited expression in Promise.

Slide 77

Slide 77 text

Wrap awaited expression in Promise. async function printOrder(orderId) { const promise = Promise.resolve( fetchOrder(orderId) ); console.log(order); } printOrder(1);

Slide 78

Slide 78 text

Wrap remaining code in a then callback. async function printOrder(orderId) { const promise = Promise.resolve( fetchOrder(orderId) ); console.log(order); } printOrder(1);

Slide 79

Slide 79 text

function printOrder(orderId) { const promise = Promise.resolve( fetchOrder(orderId) ); return promise.then(order => { console.log(order); return Promise.resolve(undefined); }); } printOrder(1); Wrap remaining code in a then callback.

Slide 80

Slide 80 text

No explicit return, so return a resolved undefined value. function printOrder(orderId) { const promise = Promise.resolve( fetchOrder(orderId) ); return promise.then(order => { console.log(order); return Promise.resolve(undefined); }); } printOrder(1);

Slide 81

Slide 81 text

Error Handling.

Slide 82

Slide 82 text

function printOrder(orderId) { fetchOrder(orderId) .then(order => console.log(order)) .catch(e => console.log('error retrieving order', e)); } async function printOrder(orderId) { try { const order = await fetchOrder(orderId); console.log(order); } catch(e) { console.log('error retrieving order', e); } }

Slide 83

Slide 83 text

function printOrder(orderId) { fetchOrder(orderId) .then(order => console.log(order)) .catch(e => console.log('error retrieving order', e)); } async function printOrder(orderId) { try { const order = await fetchOrder(orderId); console.log(order); } catch(e) { console.log('error retrieving order', e); } }

Slide 84

Slide 84 text

function printOrder(orderId) { fetchOrder(orderId) .then(order => console.log(order)) .catch(e => console.log('error retrieving order', e)); } async function printOrder(orderId) { try { const order = await fetchOrder(orderId); console.log(order); } catch(e) { console.log('error retrieving order', e); } }

Slide 85

Slide 85 text

function printOrder(orderId) { fetchOrder(orderId) .then(order => console.log(order)) .catch(e => console.log('error retrieving order', e)); } async function printOrder(orderId) { try { const order = await fetchOrder(orderId); console.log(order); } catch(e) { console.log('error retrieving order', e); } }

Slide 86

Slide 86 text

Sequential vs. Parallel

Slide 87

Slide 87 text

Sequential async function printOrders(orderIds) { const orders = []; for (const id of orderIds) { const order = await fetchOrder(id); orders.push(order); } console.log(orders); } printOrders([1, 2, 3]);

Slide 88

Slide 88 text

Sequential async function printOrders(orderIds) { const orders = []; for (const id of orderIds) { const order = await fetchOrder(id); orders.push(order); } console.log(orders); } printOrders([1, 2, 3]); Each step of loop has to wait. Issue if requests aren’t dependent on each other.

Slide 89

Slide 89 text

Parallel async function printOrders(orderIds) { const orders = await Promise.all( orderIds.map(id => fetchOrder(id)) ); console.log(orders); } printOrders([1, 2, 3]);

Slide 90

Slide 90 text

Parallel async function printOrders(orderIds) { const orders = await Promise.all( orderIds.map(id => fetchOrder(id)) ); console.log(orders); } printOrders([1, 2, 3]); Make all requests at once and resolve with Promise.all. Allows for “parallelism.”

Slide 91

Slide 91 text

Sequential vs. Parallel Demo

Slide 92

Slide 92 text

Moral: don’t use sequential awaits unless you need serialization!

Slide 93

Slide 93 text

Why Async Functions? • Synchronous-looking asynchronous code. • Gain back use of native language flow control constructs with asynchronous code (e.g. for..of, try/catch). • Asynchronous coroutines.

Slide 94

Slide 94 text

Slide 95

Slide 95 text

Other upcoming features • Stage 3: SIMD, Exponentiation operator, Array.prototype.includes • Stage 2: Object.observe • Stage 1: Typed objects, class property initializers, shared memory and atomics, Observable • Stage 0: function bind operator, do expressions • Many more!

Slide 96

Slide 96 text

Resources • https://github.com/tc39/ecma262 • http://babeljs.io/ • $ babel --stage 0 myAwesomeES7code.js • https://tc39.github.io/process-document/ • https://esdiscuss.org/ • http://www.ecma-international.org/memento/ contribute_TC39_Royalty_Free_Task_Group.php

Slide 97

Slide 97 text

Thanks! Code: github.com/jfairbank/es7-and-beyond-talk Slides:
 speakerdeck.com/jfairbank/html5devconf-es7-and-beyond Jeremy Fairbank jeremyfairbank.com @elpapapollo