Music City Code: ES7 and Beyond!

Music City Code: ES7 and Beyond!

This talks dives into some of the new (and experimental) features coming to ES7 and possibly later versions of JavaScript.

94bd558238b69c45d3d3e15797ae94f7?s=128

Jeremy Fairbank

August 29, 2015
Tweet

Transcript

  1. ES7 and Beyond! Jeremy Fairbank jeremyfairbank.com @elpapapollo

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

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

  4. ES7

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

  6. None
  7. Many proposed features, several coming after ES7.

  8. None
  9. None
  10. Transpilers • Convert ES6/ES7/ES.later code into equivalent ES5 code. •

    Babel • babeljs.io • Traceur • github.com/google/traceur-compiler
  11. TC39 Process • Five stage process for converting an idea

    to a standard feature. • https://tc39.github.io/process-document
  12. 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; }
  13. 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; } }
  14. Stage 2 - Draft • Precise syntax and semantics; initial

    spec. • Object rest and spread properties
 • Async functions
 async function loadOrders() { const orders = await fetchJson('/orders'); console.log(orders); } let obj = { ...otherObj, x: 'foo' };
  15. Stage 3 - Candidate • Completed spec; needs reviewing for

    refinements. • Exponentiation operator
 • Array.prototype.includes 3 ** 2; // 9 [1, 2, 3].includes(2); // true
  16. Stage 4 - Finished • Ready to be included in

    the next ES standard. • No proposals at Stage 4 at the moment.
  17. <stage-0>

  18. Function Bind Operator • Binary and unary double colon ::

    operator • Bind this context to a function, by desugaring to bind, call, or apply. • https://github.com/zenparsing/es-function-bind • http://blog.jeremyfairbank.com/javascript/ javascript-es7-function-bind-syntax/
  19. Call Syntax function logThis() { console.log(this); } const obj =

    { foo: 'bar' }; logThis.call(obj); // { foo: 'bar' } // Now obj::logThis(); // { foo: 'bar' }
  20. Call Syntax function logThis() { console.log(this); } const obj =

    { foo: 'bar' }; logThis.call(obj); // { foo: 'bar' } // Now obj::logThis(); // { foo: 'bar' } Normal invocations would log window or the global object.
  21. Call Syntax function logThis() { console.log(this); } const obj =

    { foo: 'bar' }; logThis.call(obj); // { foo: 'bar' } // Now obj::logThis(); // { foo: 'bar' }
  22. Call Syntax function logThis() { console.log(this); } const obj =

    { foo: 'bar' }; logThis.call(obj); // { foo: 'bar' } // Now obj::logThis(); // { foo: 'bar' }
  23. function logThis(...args) { console.log(this, ...args); } function logObj1(obj, ...args) {

    logThis.apply(obj, args); } function logObj2(obj, ...args) { obj::logThis(...args); } const obj = { foo: 'bar' }; logObj1(obj, 42, 'baz'); // { foo: 'bar' } 42 'baz' logObj2(obj, 42, 'baz'); // { foo: 'bar' } 42 'baz' Apply Syntax
  24. Apply Syntax function logThis(...args) { console.log(this, ...args); } function logObj1(obj,

    ...args) { logThis.apply(obj, args); } function logObj2(obj, ...args) { obj::logThis(...args); } const obj = { foo: 'bar' }; logObj1(obj, 42, 'baz'); // { foo: 'bar' } 42 'baz' logObj2(obj, 42, 'baz'); // { foo: 'bar' } 42 'baz'
  25. Apply Syntax function logThis(...args) { console.log(this, ...args); } function logObj1(obj,

    ...args) { logThis.apply(obj, args); } function logObj2(obj, ...args) { obj::logThis(...args); } const obj = { foo: 'bar' }; logObj1(obj, 42, 'baz'); // { foo: 'bar' } 42 'baz' logObj2(obj, 42, 'baz'); // { foo: 'bar' } 42 'baz'
  26. Bind Syntax function logThis() { console.log(this); } const obj =

    { foo: 'bar' }; const logObj1 = logThis.bind(obj); logObj1(); // { foo: 'bar' } // Now const logObj2 = obj::logThis; logObj2(); // { foo: 'bar' }
  27. Bind Syntax function logThis() { console.log(this); } const obj =

    { foo: 'bar' }; const logObj1 = logThis.bind(obj); logObj1(); // { foo: 'bar' } // Now const logObj2 = obj::logThis; logObj2(); // { foo: 'bar' }
  28. Bind Syntax No parens, so bind instead of calling. function

    logThis() { console.log(this); } const obj = { foo: 'bar' }; const logObj1 = logThis.bind(obj); logObj1(); // { foo: 'bar' } // Now const logObj2 = obj::logThis; logObj2(); // { foo: 'bar' }
  29. Explicit vs. Implicit Bind const obj = { foo: 'bar',

    log() { console.log(this.foo); } }; const unbound = obj.log; const implicitBind = ::obj.log; const explicitBind = obj::obj.log; unbound(); // undefined implicitBind(); // bar explicitBind(); // bar
  30. const obj = { foo: 'bar', log() { console.log(this.foo); }

    }; const unbound = obj.log; const implicitBind = ::obj.log; const explicitBind = obj::obj.log; unbound(); // undefined implicitBind(); // bar explicitBind(); // bar Explicit vs. Implicit Bind Lose this context
  31. Explicit vs. Implicit Bind const obj = { foo: 'bar',

    log() { console.log(this.foo); } }; const unbound = obj.log; const implicitBind = ::obj.log; const explicitBind = obj::obj.log; unbound(); // undefined implicitBind(); // bar explicitBind(); // bar Implicitly bind to obj with unary operator.
  32. Explicit vs. Implicit Bind const obj = { foo: 'bar',

    log() { console.log(this.foo); } }; const unbound = obj.log; const implicitBind = ::obj.log; const explicitBind = obj::obj.log; unbound(); // undefined implicitBind(); // bar explicitBind(); // bar Explicitly bind to obj with binary operator.
  33. Why Function Bind Operator? • Succinct syntax for call, apply,

    and bind. • Virtual methods • Use array methods on DOM node lists. • Object method chaining with real methods and third party libs like Trine. • https://github.com/jussi-kalliokoski/trine • Callbacks to other libraries.
  34. Do Expressions • Make a block an expression. • Last

    statement in the block is the “return” value. • Prepend do keyword to a block to create. • Like syntactical sugar for IIFE. • http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions
  35. Do Expressions const foo = do { const x =

    'b'; const y = 'a'; const z = 'r'; x + y + z; }; console.log(foo); // bar console.log(do { const x = 21; x * 2; }); // 42
  36. Do Expressions const foo = do { const x =

    'b'; const y = 'a'; const z = 'r'; x + y + z; }; console.log(foo); // bar console.log(do { const x = 21; x * 2; }); // 42 Locally scoped variables.
  37. Do Expressions const foo = do { const x =

    'b'; const y = 'a'; const z = 'r'; x + y + z; }; console.log(foo); // bar console.log(do { const x = 21; x * 2; }); // 42 Last statement is return value.
  38. Do Expressions const foo = do { const x =

    'b'; const y = 'a'; const z = 'r'; x + y + z; }; console.log(foo); // bar console.log(do { const x = 21; x * 2; }); // 42
  39. Ternary Alternative function readyResponse(ready) { const response = do {

    if (ready) "I'm ready. Let's go!"; else "Hold on a minute."; }; console.log(response); } readyResponse(true); // I'm ready. Let's go! readyResponse(false); // Hold on a minute.
  40. Ternary Alternative function readyResponse(ready) { const response = do {

    if (ready) "I'm ready. Let's go!"; else "Hold on a minute."; }; console.log(response); } readyResponse(true); // I'm ready. Let's go! readyResponse(false); // Hold on a minute. Each branch ends with an expression.
  41. Ternary Alternative const response = ready ? "I'm ready. Let's

    go!" : "Hold on a minute."; const response = do { if (ready) "I'm ready. Let's go!"; else "Hold on a minute."; }; Transpile
  42. </stage-0> <stage-1>

  43. 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. • https://github.com/wycats/javascript-decorators
  44. 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
  45. 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
  46. 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 Consequence: getters are nonenumerable by default.
  47. How do we normally make class/prototype getters enumerable?

  48. 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
  49. 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
  50. 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
  51. Code becomes more complex and less declarative.

  52. Decorators are the answer!

  53. 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
  54. 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
  55. 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
  56. How do decorators work?

  57. Just Functions function enumerable(target, name, descriptor) { descriptor.enumerable = true;

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

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

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

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

    } Just Functions Return is optional if you mutate descriptor. Useful if you want to create new descriptor.
  62. Just Functions @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);
  63. Just Functions @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);
  64. Just Functions @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);
  65. Just Functions @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);
  66. Decorators can take arguments too.

  67. Decorators and Arguments 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.
  68. Decorators and Arguments 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. Evaluate function call and use return value as decorator.
  69. Decorators and Arguments 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.
  70. Decorators with Parameters function alias(aliasName) { return (target, name, descriptor)

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

    => { const newDescriptor = Object.assign({}, descriptor, { value(...args) { return this[name](...args); } }); Object.defineProperty(target, aliasName, newDescriptor); }; } Take a parameter
  72. Decorators with Parameters function alias(aliasName) { return (target, name, descriptor)

    => { const newDescriptor = Object.assign({}, descriptor, { value(...args) { return this[name](...args); } }); Object.defineProperty(target, aliasName, newDescriptor); }; } Actual decorator function
  73. What about decorated classes?

  74. 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); } }
  75. 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); } } Use a decorator on the class
  76. 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); } }
  77. 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
  78. 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
  79. Why Class Decorators? • Extremely powerful and expressive syntax for

    class/property modification. • Mixins — no more fragile base class or multiple inheritance issues. • @autobind, @deprecate, @memoize, @readonly, and more! • https://github.com/jayphelps/core-decorators.js
  80. </stage-1> <stage-2>

  81. And the moment you’ve been awaiting (pun intended).

  82. 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. • https://github.com/tc39/ecmascript-asyncawait
  83. function loadOrder(orderId) { fetchJson(`/orders/${orderId}`) .then(order => console.log(order)); } loadOrder(1);

  84. function loadOrder(orderId) { fetchJson(`/orders/${orderId}`) .then(order => console.log(order)); } async function

    loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order); } loadOrder(1);
  85. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } loadOrder(1);
  86. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } loadOrder(1); Declare a function as async
  87. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } loadOrder(1); Await a promise and obtain the fulfilled/resolved value. Nonblocking.
  88. How do async functions work?

  89. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } loadOrder(1);
  90. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } loadOrder(1); Invoke function.
  91. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } loadOrder(1); Encounter await.
  92. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } loadOrder(1); Wrap awaited expression in Promise.
  93. Wrap awaited expression in Promise. async function loadOrder(orderId) { const

    promise = Promise.resolve( fetchJson(`/orders/${orderId}`) ); console.log(order); } loadOrder(1);
  94. Wrap remaining code in a then callback. async function loadOrder(orderId)

    { const promise = Promise.resolve( fetchJson(`/orders/${orderId}`) ); console.log(order); } loadOrder(1);
  95. Wrap remaining code in a then callback. function loadOrder(orderId) {

    const promise = Promise.resolve( fetchJson(`/orders/${orderId}`) ); return promise.then(order => { console.log(order); return Promise.resolve(undefined); }); } loadOrder(1);
  96. No explicit return, so return a resolved undefined value. function

    loadOrder(orderId) { const promise = Promise.resolve( fetchJson(`/orders/${orderId}`) ); return promise.then(order => { console.log(order); return Promise.resolve(undefined); }); } loadOrder(1);
  97. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } function loadOrder(orderId) { const promise = Promise.resolve( fetchJson(`/orders/${orderId}`) ); return promise.then(order => { console.log(order); return Promise.resolve(undefined); }); } Final equivalent-ish code
  98. async function loadOrder(orderId) { const order = await fetchJson(`/orders/${orderId}`); console.log(order);

    } function loadOrder(orderId) { const promise = Promise.resolve( fetchJson(`/orders/${orderId}`) ); return promise.then(order => { console.log(order); return Promise.resolve(undefined); }); } What does this function look like?
  99. Multiple Awaits async function fetchJson(url) { const resp = await

    fetch(url); const data = await resp.json(); const isSuccess = resp.status >= 200 && resp.status < 300; if (isSuccess) { return data; } const error = new Error(resp.responseText); error.data = data; throw error; }
  100. Multiple Awaits async function fetchJson(url) { const resp = await

    fetch(url); const data = await resp.json(); const isSuccess = resp.status >= 200 && resp.status < 300; if (isSuccess) { return data; } const error = new Error(resp.responseText); error.data = data; throw error; } Potential for dependency means sequential awaits are NOT parallel!
  101. Multiple Awaits async function fetchJson(url) { const resp = await

    fetch(url); const data = await resp.json(); const isSuccess = resp.status >= 200 && resp.status < 300; if (isSuccess) { return data; } const error = new Error(resp.responseText); error.data = data; throw error; }
  102. Multiple Awaits async function fetchJson(url) { const resp = await

    fetch(url); const data = await resp.json(); const isSuccess = resp.status >= 200 && resp.status < 300; if (isSuccess) { return data; } const error = new Error(resp.responseText); error.data = data; throw error; } What will happen?
  103. How do we handle errors/exceptions in synchronous code?

  104. Error Handling async function loadOrder(orderId) { try { const order

    = await fetchJson(`/orders/${orderId}`); console.log(order); } catch(e) { console.log('error retrieving order', e.data); } } loadOrder(1);
  105. Error Handling async function loadOrder(orderId) { try { const order

    = await fetchJson(`/orders/${orderId}`); console.log(order); } catch(e) { console.log('error retrieving order', e.data); } } loadOrder(1); Promise was resolved
  106. Error Handling async function loadOrder(orderId) { try { const order

    = await fetchJson(`/orders/${orderId}`); console.log(order); } catch(e) { console.log('error retrieving order', e.data); } } loadOrder(1); Promise was rejected
  107. function loadOrder(orderId) { fetchJson(`/orders/${orderId}`) .then(order => console.log(order)) .catch(e => console.log('error

    retrieving order', e.data)); } async function loadOrder(orderId) { try { const order = await fetchJson(`/orders/${orderId}`); console.log(order); } catch(e) { console.log('error retrieving order', e.data); } }
  108. function loadOrder(orderId) { fetchJson(`/orders/${orderId}`) .then(order => console.log(order)) .catch(e => console.log('error

    retrieving order', e.data)); } async function loadOrder(orderId) { try { const order = await fetchJson(`/orders/${orderId}`); console.log(order); } catch(e) { console.log('error retrieving order', e.data); } }
  109. function loadOrder(orderId) { fetchJson(`/orders/${orderId}`) .then(order => console.log(order)) .catch(e => console.log('error

    retrieving order', e.data)); } async function loadOrder(orderId) { try { const order = await fetchJson(`/orders/${orderId}`); console.log(order); } catch(e) { console.log('error retrieving order', e.data); } }
  110. function loadOrder(orderId) { fetchJson(`/orders/${orderId}`) .then(order => console.log(order)) .catch(e => console.log('error

    retrieving order', e.data)); } async function loadOrder(orderId) { try { const order = await fetchJson(`/orders/${orderId}`); console.log(order); } catch(e) { console.log('error retrieving order', e.data); } }
  111. What happens with explicit returns?

  112. Explicit Returns async function life() { return 42; } const

    answer = life();
  113. Explicit Returns async function life() { return 42; } const

    answer = life(); What is the value of answer?
  114. Explicit Returns async function life() { return 42; } const

    answer = life(); assert(answer !== 42); assert(answer instanceof Promise); answer.then(value => assert(value === 42));
  115. Explicit Returns async function life() { return 42; } Remember

    that async functions wrap the return value with Promise.resolve. function life() { return Promise.resolve(42); }
  116. Returning back to multiple awaits.

  117. Sequential vs. Parallel async function loadOrders(orderIds) { const orders =

    []; for (const id of orderIds) { const order = await fetchJson(`/orders/${id}`); orders.push(order); } console.log(orders); } loadOrders([1, 2, 3]);
  118. Sequential vs. Parallel async function loadOrders(orderIds) { const orders =

    []; for (const id of orderIds) { const order = await fetchJson(`/orders/${id}`); orders.push(order); } console.log(orders); } loadOrders([1, 2, 3]); Each step of loop has to wait. Issue if requests aren’t dependent on each other.
  119. async function loadOrders(orderIds) { const orders = await Promise.all(orderIds.map(id =>

    { return fetchJson(`/orders/${id}`); })); console.log(orders); } loadOrders([1, 2, 3]); Sequential vs. Parallel
  120. Sequential vs. Parallel async function loadOrders(orderIds) { const orders =

    await Promise.all(orderIds.map(id => { return fetchJson(`/orders/${id}`); })); console.log(orders); } loadOrders([1, 2, 3]); Make all requests at once and resolve with Promise.all. Allows for parallelism.
  121. Sequential vs. Parallel Demo

  122. Sequential Queue Request /orders/1
 (wait: 0s) Requests Request /orders/2
 (wait:

    0s) Request /orders/3
 (wait: 0s) Finished Time Total: 0s
  123. Sequential Queue Requests Request /orders/3
 (wait: 0s) Finished Request /orders/1


    (wait: 0s) Time Total: 0s Request /orders/2
 (wait: 0s)
  124. Sequential Queue Requests Finished Request /orders/1
 (wait: 0s, resp: 1s)

    Time Total: 1s Request /orders/2
 (wait: 1s) Request /orders/3
 (wait: 1s)
  125. Sequential Queue Requests Finished Request /orders/1
 (wait: 0s, resp: 1s)

    Time Total: 1s Request /orders/2
 (wait: 1s) Request /orders/3
 (wait: 1s)
  126. Sequential Queue Requests Finished Request /orders/1
 (wait: 0s, resp: 1s)

    Time Total: 7s Request /orders/2
 (wait: 1s, resp: 6s) Request /orders/3
 (wait: 7s)
  127. Sequential Queue Requests Request /orders/3
 (wait: 7s) Finished Request /orders/1


    (wait: 0s, resp: 1s) Time Total: 7s Request /orders/2
 (wait: 1s, resp: 6s)
  128. Sequential Queue Requests Request /orders/3
 (wait: 7s, resp: 2s) Finished

    Request /orders/1
 (wait: 0s, resp: 1s) Time Total: 9s Request /orders/2
 (wait: 1s, resp: 6s)
  129. Sequential Queue Requests Request /orders/3
 (wait: 7s, resp: 2s) Finished

    Request /orders/1
 (wait: 0s, resp: 1s) Time Total: 9s Request /orders/2
 (wait: 1s, resp: 6s) Limited by response time of every request.
  130. Parallel Queue Request /orders/1
 (wait: 0s) Requests Request /orders/2
 (wait:

    0s) Request /orders/3
 (wait: 0s) Finished Time Total: 0s
  131. Parallel Queue Request /orders/1
 (wait: 0s) Requests Request /orders/2
 (wait:

    0s) Request /orders/3
 (wait: 0s) Finished Time Total: 0s
  132. Parallel Queue Request /orders/2
 (wait: 0s) Requests Request /orders/3
 (wait:

    0s) Finished Time Total: 1s Request /orders/1
 (wait: 0s, resp: 1s)
  133. Parallel Queue Request /orders/2
 (wait: 0s) Requests Request /orders/3
 (wait:

    0s, resp: 2s) Finished Time Total: 2s Request /orders/1
 (wait: 0s, resp: 1s)
  134. Parallel Queue Request /orders/2
 (wait: 0s, resp: 6s) Requests Request

    /orders/3
 (wait: 0s, resp: 2s) Finished Time Total: 6s Request /orders/1
 (wait: 0s, resp: 1s)
  135. Parallel Queue Request /orders/2
 (wait: 0s, resp: 6s) Requests Request

    /orders/3
 (wait: 0s, resp: 2s) Finished Time Total: 6s Request /orders/1
 (wait: 0s, resp: 1s) Limited by slowest request instead of every request.
  136. Moral: don’t use sequential awaits unless you need to!

  137. 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).
  138. </stage-2>

  139. Other upcoming features • Stage 3: Exponentiation operator, Array.prototype.includes •

    Stage 2: Object.observe, SIMD • Stage 1: Object rest and spread properties, typed objects, Observable • Stage 0: Shared memory and atomics, class property initializers • Many more!
  140. 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
  141. Questions?

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