TC39, ECMAScript, and the Future of JavaScript

TC39, ECMAScript, and the Future of JavaScript

We’ll start by glancing at the TC39 proposal revision process – how new features are proposed, how proposals move through revision stages, and why some make the cut while others don’t. Then we’ll have a look at a few proposals in the pipeline – like object spread, async iterators, async generators, and *import()*. Last, we’ll move to more exciting stuff – automated code style fixes, compile-time startup optimizations, and the future of writing JavaScript code.

550d0153dbeee2fcaede98f906e55d02?s=128

Nicolás Bevacqua

June 24, 2017
Tweet

Transcript

  1. TC39, ECMAScript, and the Future of JavaScript

  2. ponyfoo.com twitter.com/nzgb

  3. ponyfoo.com/books

  4. What’s TC39?

  5. isNaN(NaN) // true isNaN(“A”) // true “A” == NaN //

    false “A” === NaN // false NaN === NaN // false … Solution: Number.isNaN(“A”) // false Number.isNaN(NaN) // true
  6. isNaN(NaN) // true isNaN(“A”) // true “A” == NaN //

    false “A” === NaN // false NaN === NaN // false … Solution: Number.isNaN(“A”) // false Number.isNaN(NaN) // true
  7. isNaN(NaN) // true isNaN(“A”) // true “A” == NaN //

    false “A” === NaN // false NaN === NaN // false … Solution: Number.isNaN(“A”) // false Number.isNaN(NaN) // true
  8. isNaN(NaN) // true isNaN(“A”) // true “A” == NaN //

    false “A” === NaN // false NaN === NaN // false … Solution: Number.isNaN(“A”) // false Number.isNaN(NaN) // true
  9. +0 == -0 // true +0 === -0 // true

    1/+0 === 1/-0 // false
  10. Write valid JavaScript with only +!()[] jsfuck.com

  11. Specification Development Process

  12. Living Standard tc39.github.io/ecma262 github.com/tc39/proposals

  13. Stage 0

  14. Stage 1

  15. Stage 2

  16. Stage 3

  17. Stage 4

  18. prop-tc39.now.sh

  19. Release Cadence

  20. Proposals

  21. Array#includes (Stage 4) [1,2].indexOf(2) !== -1 // true [1,2].indexOf(3) !==

    -1 // false [1,2].includes(2) // true [1,2].includes(3) // false
  22. Array#includes (Stage 4) [1,2].indexOf(2) !== -1 // true [1,2].indexOf(3) !==

    -1 // false [1,2].includes(2) // true [1,2].includes(3) // false
  23. Async Functions (Stage 4) fetch(‘/api/products’) .then(res => res.json()) .then(data =>

    {
 updateView(data) }) .catch(err => { console.log(‘Update failed’, err) })
  24. Async Functions (Stage 4) fetch(‘/api/products’) .then(res => res.json()) .then(data =>

    {
 updateView(data) }) .catch(err => { console.log(‘Update failed’, err) })
  25. Async Functions (Stage 4) fetch(‘/api/products’) .then(res => res.json()) .then(data =>

    {
 updateView(data) }) .catch(err => { console.log(‘Update failed’, err) })
  26. Async Functions (Stage 4) fetch(‘/api/products’) .then(res => res.json()) .then(data =>

    {
 updateView(data) }) .catch(err => { console.log(‘Update failed’, err) })
  27. Async Functions (Stage 4) await fetch(‘/api/products’) .then(res => res.json()) .then(data

    => {
 updateView(data) }) .catch(err => { console.log(‘Update failed’, err) })
  28. Async Functions (Stage 4) const res = await fetch(‘/api/products’) .then(res

    => res.json()) .then(data => {
 updateView(data) }) .catch(err => { console.log(‘Update failed’, err) })
  29. Async Functions (Stage 4) const res = await fetch(‘/api/products’) const

    data = await res.json() .then(data => {
 updateView(data) }) .catch(err => { console.log(‘Update failed’, err) })
  30. Async Functions (Stage 4) const res = await fetch(‘/api/products’) const

    data = await res.json()
 updateView(data) .catch(err => { console.log(‘Update failed’, err) })
  31. Async Functions (Stage 4) try { const res = await

    fetch(‘/api/products’) const data = await res.json()
 updateView(data) } catch(err) { console.log(‘Update failed’, err) }
  32. Async Functions (Stage 4) async function main() { try {

    const res = await fetch(‘/api/products’) const data = await res.json()
 updateView(data) } catch(err) { console.log(‘Update failed’, err) } }
  33. Async Functions (Stage 4) (async () => { try {

    const res = await fetch(‘/api/products’) const data = await res.json()
 updateView(data) } catch(err) { console.log(‘Update failed’, err) } })()
  34. Async Functions (Stage 4) (async () => { try {

    const res = await fetch(‘/api/products’) const data = await res.json()
 updateView(data) } catch(err) { console.log(‘Update failed’, err) } })() await (2 + 3)
  35. Async Functions (Stage 4) (async () => { try {

    const res = await fetch(‘/api/products’) const data = await res.json()
 updateView(data) } catch(err) { console.log(‘Update failed’, err) } })() `Price: ${ await getPrice() }`
  36. Async Functions (Stage 4) (async () => { try {

    const res = await fetch(‘/api/products’) const data = await res.json()
 updateView(data) } catch(err) { console.log(‘Update failed’, err) } })() renderView(await getPrice())
  37. Async Functions (Stage 4) (async () => { try {

    const res = await fetch(‘/api/products’) const data = await res.json()
 updateView(data) } catch(err) { console.log(‘Update failed’, err) } })() 2 * (await getPrice())
  38. Async Functions (Stage 4) const sleep = delay => new

    Promise(resolve => setTimeout(resolve, delay) ) const slowLog = async (...terms) => { await sleep(2000) console.log(...terms) } slowLog(‘Well that was underwhelming’) .then(() => console.log(‘Nailed it!’)) .catch(reason => console.error(‘Failed’, reason))
  39. Async Iteration (Stage 3) const list = { [Symbol.iterator]() {

    let i = 0 return { next: () => ({ value: i++, done: i > 5 }) } } } [...list] // <- [0, 1, 2, 3, 4] Array.from(list) // <- [0, 1, 2, 3, 4] for (const i of list) { // <- 0, 1, 2, 3, 4 }
  40. Async Iteration (Stage 3) const list = { [Symbol.iterator]() {

    let i = 0 return { next: () => ({ value: i++, done: i > 5 }) } } } [...list] // <- [0, 1, 2, 3, 4] Array.from(list) // <- [0, 1, 2, 3, 4] for (const i of list) { // <- 0, 1, 2, 3, 4 }
  41. Async Iteration (Stage 3) const list = { [Symbol.iterator]() {

    let i = 0 return { next: () => ({ value: i++, done: i > 5 }) } } } [...list] // <- [0, 1, 2, 3, 4] Array.from(list) // <- [0, 1, 2, 3, 4] for (const i of list) { // <- 0, 1, 2, 3, 4 }
  42. Async Iteration (Stage 3) const list = { [Symbol.asyncIterator]() {

    let i = 0 return { next: () => Promise.resolve({ value: i++, done: i > 5 }) } } }
  43. Async Iteration (Stage 3) const list = { [Symbol.asyncIterator]() {

    let i = 0 return { next: () => Promise.resolve({ value: i++, done: i > 5 }) } } } for await (const i of items) { // <- 0, 1, 2, 3, 4 }
  44. Async Iteration (Stage 3) const list = { [Symbol.asyncIterator]() {

    let i = 0 return { next: () => Promise.resolve({ value: i++, done: i > 5 }) } } } async function readItems() { for await (const i of items) { // <- 0, 1, 2, 3, 4 } }
  45. Async Iteration (Stage 3) async function* getProducts(categoryUrl) { const listReq

    = await fetch(categoryUrl) const list = await listReq.json() for (const product of list) { const productReq = await product.url const product = await productReq.json() yield product } }
  46. Async Iteration (Stage 3) async function* getProducts(categoryUrl) { const listReq

    = await fetch(categoryUrl) const list = await listReq.json() for (const product of list) { const productReq = await product.url const product = await productReq.json() yield product } } async function readProducts() { const g = getProducts(category) for await (const product of g) { // use product details } }
  47. Rest/Spread Properties (Stage 3) Object.assign( {}, { a: "a" },

    { b: "b" }, { a: "c" } ) { ...{ a: "a" }, ...{ b: "b" }, ...{ a: "c" } } // <- { a: "c", b: "b"}
  48. Rest/Spread Properties (Stage 3) Object.assign( {}, { a: "a" },

    { b: "b" }, { a: "c" } ) { ...{ a: "a" }, ...{ b: "b" }, ...{ a: "c" } } // <- { a: "c", b: "b"}
  49. Rest/Spread Properties (Stage 3) Object.assign( {}, { a: "a" },

    { b: "b" }, { a: "c" } ) { ...{ a: "a" }, ...{ b: "b" }, ...{ a: "c" } } // <- { a: "c", b: "b"}
  50. Rest/Spread Properties (Stage 3) const item = { id: '4fe09c27',

    name: 'Banana', amount: 3 } const { id, ...rest } = item // <- { name: 'Banana', amount: 3 }
  51. Rest/Spread Properties (Stage 3) function print({ id, ...rest }) {

    console.log(rest) } print({ id: '4fe09c27', name: 'Banana' }) // <- { name: 'Banana'}
  52. Dynamic import() (Stage 3) import markdown from './markdown' // ...

    export default compile
  53. Dynamic import() (Stage 3) import(`./i18n.${ navigator.language }.js`) .then(module => console.log(module.messages))

    .catch(reason => console.error(reason))
  54. Named Captures (Stage 3) const urlRegExp = /^(?: (http[s]?|ftp):\/)?\/?([^:\/ \s]+)((?:\/\w+)*\/)([\w\-\.]+

    [^#?\s]+)([^#]*)?(#[\w\-]+)?$/
  55. Named Captures (Stage 3) const urlRegExp = /^(?:(? <protocol>http[s]?|ftp):\/)? \/?(?<host>[^:\/\s]+)(?

    <path>(?:\/\w+)*\/)(? <file>[\w\-\.]+[^#?\s]+)(? <query>[^#]*)?(?<hash>#[\w\-] +)?$/u
  56. Named Captures (Stage 3) const urlRegExp = /^(?<url>(? <protocol>http[s]?|ftp):\/)? \/?(?<host>[^:\/\s]+)(?

    <path>(?:\/\w+)*\/)(? <file>[\w\-\.]+[^#?\s]+)(? <query>.*)?(?<hash>#[\w\-]+)? $/ const url = 'https://commits.com/8b48e3/diff?w=1#readme' const { groups } = urlRegExp.exec(url) console.log(groups) { protocol: 'https', host: 'commits.com', path: '/8b48e3/', file: 'diff', query: '?w=1', hash: '#readme' }
  57. Named Captures (Stage 3) const urlRegExp = /^(?<url>(? <protocol>http[s]?|ftp):\/)? \/?(?<host>[^:\/\s]+)(?

    <path>(?:\/\w+)*\/)(? <file>[\w\-\.]+[^#?\s]+)(? <query>.*)?(?<hash>#[\w\-]+)? $/ const url = 'https://commits.com/8b48e3/diff?w=1#readme' const pattern = '$<protocol>://github.com/$<file>' const replaced = url.replace(urlRegExp, pattern) console.log(replaced) // <- 'https://github.com/diff'
  58. Named Captures (Stage 3) const urlRegExp = /^(?<url>(? <protocol>http[s]?|ftp):\/)? \/?(?<host>[^:\/\s]+)(?

    <path>(?:\/\w+)*\/)(? <file>[\w\-\.]+[^#?\s]+)(? <query>.*)?(?<hash>#[\w\-]+)? $/ const duplicateRegExp = /^(.*)=\1$/ const duplicateRegExp = /^(?<thing>.*)=\k<thing>$/u duplicateRegExp.test('a=b') // <- false duplicateRegExp.test('a=a') // <- true duplicateRegExp.test('aa=a') // <- false duplicateRegExp.test('bbb=bbb') // <- true
  59. Unicode Escapes (Stage 3) /^\p{Script=Greek}$/u.test('π') // <- true /^\P{Script=Greek}$/u.test('π') //

    <- false
  60. Lookbehind Assertions (Stage 3) /\d+/.test('¥1245') // <- true /(?<!¥)\d+/.test('¥1245') //

    <- false /(?<!¥)\d+/.test('$1245') // <- true
  61. Lookbehind Assertions (Stage 3) /\d+/.test('¥1245') // <- true /(?<!¥)\d+/.test('¥1245') //

    <- false /(?<!¥)\d+/.test('$1245') // <- true /(?<=¥)\d+/.test('¥1245') // <- true /(?<=¥)\d+/.test('$1245') // <- false
  62. Class Decorators (Stage 2) @pure @decorators.elastic() class View { @throttle(200)

    reconcile() { } }
  63. Class Decorators (Stage 2) @pure @decorators.elastic() class View { @throttle(200)

    reconcile() { } } function readonly({ descriptor, ...rest }) { return { ...rest, descriptor: { ...descriptor, writable: false } } }
  64. Promise#finally (Stage 2) showSpinner() fetch(productUrl) .then(renderProduct) .then( hideSpinner, hideSpinner )

  65. Promise#finally (Stage 2) showSpinner() fetch(productUrl) .then(renderProduct) .finally( hideSpinner )

  66. Future of JavaScript

  67. None
  68. None
  69. None
  70. None
  71. None
  72. None
  73. None
  74. None
  75. None
  76. None
  77. Prepack

  78. Resources ponyfoo.com/articles/es6 ponyfoo.com/articles/understanding-javascript-async-await ponyfoo.com/articles/regular-expressions-post-es6 ponyfoo.com/articles/standard ponyfoo.com/articles/javascript-asynchronous-iteration-proposal ponyfoo.com/books/practical-modern-javascript/chapters prop-tc39.now.sh github.com/tc39/proposals twitter.com/nzgb

  79. Thanks!