1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【視聴メモ】 What’s new in JavaScript (Google I/O '19)

Last updated at Posted at 2019-05-11

この記事は Google I/O '19 のセッションの視聴メモです。
想定読者は自分なので正確性や網羅率には問題があるかもしれません。


Reference

Speakers

Abstract

このプレゼンテーションではモダンなWebサイトとNodeアプリケーションを作るためのJavaScriptの開発手法を紹介します。ChromeとNodeに近日登場する機能と、V8がそれらのためにどんな最適化をしているのか、また実際の開発においてWebとNodeのアプリケーションのパフォーマンスと安定性をどう改善しているのかという点がわかります。

Contents

image.png

V8のパフォーマンス改善

  • Chrome 61 (2017/09) と Chrome 75 (2019/06) を比べるとパースは2倍以上速くなった
  • Node 7 (2016/10) と Node 12 (2019/04) を比べると Promise や async/await の実行は11倍(300ms→30ms)速くなった
  • Chrome 60 (2017/07) と Chrome76 (2019/07) を比べるとメモリ使用量は20%ほど減少した

New JS Features

  • async iterators / async generators
  • Promise#finally
  • optional catch binding
    • try-catch でエラーを使わないときエラー変数を定義しなくても良い構文
  • String#trimStart / String#trimEnd
  • object rest & spread

class fields

  • クラスフィールドがpublicとprivateで定義できるようになった
  • privateフィールドにスコープ外からアクセスするとSyntaxErrorになる。
  • this.#<filed> という形でなければアクセスできないのは自明なので良さそう。
class IncreasingCounter {
  #count = 0;
  get values() {
    console.log('Getting the current value!');
    return this.#count;
  }
  increment() {
    this.#count++;
  }
}

const counter = new IncreasingCounter();
counter.#count; // -> SyntaxError

String#matchAll

正規表現に関する新機能

  • String#match はマッチした文字列しか取得できない
    • マッチした位置などの詳細を知れない
  • String#exec はwhileループで書かないといけない
    • 配列で取得できない
  • String#matchAll はマッチの結果を詳細と共に取得できて配列にもなる
    • capture group と一緒に使うと match.groups.<group-name>でマッチ部分を名前付けして取得できる
const string = 'Favorite GitHub repos: tc39/ecma262 v8/v8.dev';
const regex = /\b(?<owner>[a-z0-9]+)\/(?<repo>[a-z0-9\.]+)\b/g;
for (const match of string.matchAll(regex)) {
  console.log(`${match[0]} at ${match.index} with '${match.input}'`);
  console.log(`→ owner: ${match.groups.owner}`);
  console.log(`→ repo: ${match.groups.repo}`);
}

BigInt

  • 数字をアンダーバーで区切って見やすくする 123_456_789
  • 数字にnサフィックスでBigIntになる 123_456_789n
  • 区切る書き方と併用できるようになった
    • BigInt#toLocaleString
      • ロケールを意識して数字を区切ってくれる
    • Intl.NumberFormat
  • JSBI: BigInt のポリフィル

Array#flatMap

  • [...].flat(<number>) で配列中の配列も再帰的に展開可能になった
    • 引数に Infinity を指定するとできる限り展開するようになる

Object#fromEntries

  • Object#entries の逆
  • Map からオブジェクトを生成することもできる

globalThis

  • あらゆる環境でグローバルオブジェクトを取得するコードを実装するのは大変

Stable sort

  • Array#sort が安定ソートになった

Intl

  • i18nのための機能
  • Intl.RelativeTimeFormat
    • 1日前が yesterday になったり 昨日 になったりする
  • サードパーティーライブラリで対応するにはロケールファイルをダウンロードする必要があるので、標準で対応していると嬉しい
  • Intl.ListFormat
    • "a, b, c" が "a, b, or c" にフォーマットされる
    • 日本語だと微妙な感じに…
      • lf.format([ '東京', '大阪', '福岡' ]) // => "東京、大阪、または福岡"
  • Intl.DateTimeFormat#formatRange
    • "2019年5月7日から5月9日" が "May 5-7, 2019" にフォーマットされる
      • flagを有効にしないと確認できなかったので日本語でどうなるかは未確認
  • Intl.Locale
    • ロケールごとの言語やカレンダーシステム、時間周期を設定できるインターフェイス

Top level await

  • 現状ではトップレベルにawaitは書けない
  • ワークアラウンドとして、トップレベルの処理をすべてのasync関数で囲って即時実行するというものがある
  • あまり意味のない手間なのでトップレベルでawaitを書けるようにする
  • Chromeコンソールはすでにasync関数で覆われて実行されているのでトップレベルawaitが実行できるが、他の環境では対応していない

Promise APIs

  • Promise.all - Promiseが1つでもrejectされたとき止まる
  • Promise.race - Promiseが1つでも終了(reject含む)したとき止まる
  • Promise.allSettled - すべてのPromiseが終了したとき止まる
  • Promise.any - Promiseが1つでも終了(reject含まない)したとき止まる

WeakRef

  • 使われてないエントリーが勝手にガベージコレクションされる
  • Mapと組み合わせるとメモリに優しいキャッシュができる
const cache = new Map();
    
function getImageCached(name) {
  let ref = cache.get(name);
  if (ref !== undefined) {
    const deref = ref.deref();
    if (deref !== undefined) return deref;
  }
  const image = perfomeExpensiveOperation(name);
  ref = new WeakRef(image);
  cache.set(name, ref);
  return image;
}
  • keyの方はただのstringなので保存され続けるがどうするか → FinalizationGroup を使う
  • FinalizationGroup は登録した値が開放されたときにコールバックを呼べる
const finalizationGroup = new FinalizationGroup((iterator) => {
  for (const name of iterator) {
    const ref = cache.get(name);
    if (ref !== undefined && ref.deref() === undefined) {
      cache.delete(name);
    }
  }
});
    
// Exec finalizationGroup.register(image, name) after cache.set(name, ref);
// 第1引数の値が開放されたときに第2引数を元にコールバックが呼ばれる
// そのとき第1引数はすでに開放されているので第1引数を識別するような第2引数が必要になる
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?