100
JavaScript 2013 ECMAScript 6th & JavaScript Fast Parts @HTML5 Conference 2013 by Tomoya Asai (dynamis) Last Update: 2013/12/11 ECMA-262 6 th Edition / Draft November 8, 2013 ECMAScript Language Specification Draft Ecma/TC39/2013/0xx Draft

JavaScript (ECMAScript) 2013

  • Upload
    dynamis-

  • View
    11.746

  • Download
    7

Embed Size (px)

DESCRIPTION

HTML5 Conference 2013 で使用したスライド (2013/12/11 Updated) http://events.html5j.org/conference/2013/11/

Citation preview

Page 1: JavaScript (ECMAScript) 2013

JavaScript 2013ECMAScript 6th & JavaScript Fast Parts

@HTML5 Conference 2013 by Tomoya Asai (dynamis)

Last Update: 2013/12/11

Reference number ECMA-123:2009

© Ecma International 2009

ECMA-262 6th Edition / Draft November 8, 2013

ECMAScript Language Specification

Draft

Ecma/TC39/2013/0xx

Draft Report Errors and Issues at: https://bugs.ecmascript.org

Product: Draft for 6th Edition Component: choose an appropriate one Version: Rev 21, November 8, 2013 Draft

Page 2: JavaScript (ECMAScript) 2013

about:me

Page 3: JavaScript (ECMAScript) 2013

Tomoya ASAI

Mozilla Japan Technical Marketing (Evangelist) dynamis @ community dynamis.jp @dynamitter facebook.com/dynamis

mailto: Tomoya ASAI <dynamis mozilla-japan.org>@

Page 4: JavaScript (ECMAScript) 2013

Topics

Page 5: JavaScript (ECMAScript) 2013

今日のトピック

ステキな新機能 Syntax Sugar Class & Module Readable Code

高速化の行方 Slow Parts & Fast Parts asm.js Faster JavaScript

Page 6: JavaScript (ECMAScript) 2013

今日扱わないトピック

ECMAScript 6 に至る歴史 いろいろ泣ける話があった… 過去の講演スライド参照してね

ECMAScript 5.1 までの機能 IE とか Safari が最近対応したばかりとか未実装あるけど割愛 過去の講演スライド参照してね

Page 7: JavaScript (ECMAScript) 2013

今日扱わないトピック

説明しても楽しくない機能 API Improvement Internationalization / Globalization

未合意の機能 (strawman) Pallarelism

ECMAScript 7th の機能 PromiseResolver

Page 8: JavaScript (ECMAScript) 2013

See Also...

Page 9: JavaScript (ECMAScript) 2013

JavaScript.Next Returns

2012 年時点の次世代 JS 解説 JavaScript の歴史も紹介 ECMAScript 5 も一部解説 ES5 も知らない人は先にこちらを見てからの方が良いかも

http://www.slideshare.net/dynamis/javascriptnext-returns

Page 10: JavaScript (ECMAScript) 2013

Firefox 開発ツール

標準開発ツールの紹介 一昔前とは全然違う

Firebug ユーザもご一読あれ 上手く使い分けてね

スクラッチパッドもオススメ このスライドでは紹介してないけどコードサンプルのテストに最適

http://www.slideshare.net/chikoski/firefox-28137532

Page 11: JavaScript (ECMAScript) 2013

ECMAScript 6th & Harmony

Page 12: JavaScript (ECMAScript) 2013

JavaScript の課題

仕様上高速化が困難 モジュール性の不足 プロトタイプベースの特殊性 不可思議な this の挙動 Array じゃない Array like 達 非同期処理コールバック地獄 実行時エラーが多い

Page 13: JavaScript (ECMAScript) 2013

JavaScript 改良への動き

~2008 ECMAScript 4th 終了 Yahoo! & MS の反対で挫折

ECMAScript Harmony へ 次世代 ECMAScript コードネーム

2009.12 ECMAScript 5th 小さな変更だけの ES3.1 ベース

2013? ECMAScript 6th 遂に抜本的な改定の時が来た!

ECMAScript の標準化は TC39 の 2 ヶ月に1度のミーティングと ML で議論

Page 14: JavaScript (ECMAScript) 2013

ECMAScript 6th の目標

より開発しやすい言語 想定用途: 複雑なアプリ、ライブラリ、機械生成コードの実行環境

テスト可能な仕様 相互運用性を確保 バージョニングは単純に 静的検証も可能に 実行よりコンパイル時にエラー検出

http://wiki.ecmascript.org/doku.php?id=harmony:harmony

Page 15: JavaScript (ECMAScript) 2013

破棄・断念された提案

typeof null 最初の誤りを訂正したかった… 非互換性が大きすぎる

Proxies Direct Proxies に移行

Pragma モードはなるべく少なく

Page 16: JavaScript (ECMAScript) 2013

Can I Use?

Page 17: JavaScript (ECMAScript) 2013

http://kangax.github.io/es5-compat-table/es6/

ところどころウソもあるけど まぁだいたいこんな対応状況

Page 18: JavaScript (ECMAScript) 2013

実装・対応状況

SpiderMonkey がリード V8 がそれに続く JavaScriptCore や IE は限定的 先行するところも一応ある

Traceur は結構対応してる TypeScript は限定的な対応だが JavaScript に変換したコードが綺麗なのがステキ

Page 19: JavaScript (ECMAScript) 2013

ECMAScript 5th にコンパイル

Traceur Compiler ES Harmony からのコンパイル用 https://github.com/google/traceur-compiler

TypeScript ES Harmony の一部+独自拡張 http://typescriptlang.org/

たまに紹介されてる Harmonizr や Six は開発終了したっぽい

Page 20: JavaScript (ECMAScript) 2013

特定機能向けコンパイル

defs.js let, const だけ変換 https://github.com/olov/defs

es6-module-loader Module の import/export を処理 https://github.com/ModuleLoader/es6-module-loader

その他色々…

Page 21: JavaScript (ECMAScript) 2013

Shim (Polyfill) で拡張

新しい API や型の一部はプロトタイプ拡張で対応できる この方式では構文変化は対応不可

es6-shim https://github.com/paulmillr/es6-shim

ECMAScript-6 https://github.com/monolithed/ECMAScript-6

Page 22: JavaScript (ECMAScript) 2013

Syntax Sugar

Page 23: JavaScript (ECMAScript) 2013

分割代入 (Destructuring)

代入左辺を配列やオブジェクトのように書ける記法 Firefox に続けて Safari が対応但し仕様準拠はまだ不完全

複数の値のやり取りに便利 一行で済むし見やすくなる

一部の値だけ欲しいとき便利 特に JSON データ処理など

http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

Page 24: JavaScript (ECMAScript) 2013

分割代入 (Destructuring)

// 配列で受け取るサンプル: // 値の入れ替え [a, b] = [b, a]; !

// 関数から複数の値を返して一気に変数に代入 var [c,d] = (function f() { return [1,2]; })(); // -> c=1, d=2 !

// 一部省略や入れ子も可能 var [e,,[x,y]] = (function f(){ return [3,4,[10,20]] })(); // -> e=3,x=10,y=20

http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

Page 25: JavaScript (ECMAScript) 2013

分割代入 (Destructuring)

// オブジェクトで受け取るサンプル var fx={ name:"Firefox", vendor:"Mozilla", ver:26 }; var ch={ name:"Chrome", vendor:"Google", ver:31 }; var browsers={ firefox: fx, chrome: ch }; !

// 欲しいプロパティだけ一括代入 var { name: n, ver: v } = fx; // -> n="Firefox", v=26 !

// 関数の引数から必要なプロパティだけ受け取る (function ({ vendor: ven }) { console.log(ven); })(fx); // -> "Mozilla"

http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

Page 26: JavaScript (ECMAScript) 2013

未実装や議論中の構文例

// 最終的にどうなるか分かってません m(_ _)m !

// default value let { foo = 10, bar = 5 } = { foo: 12 }; console.log(foo); // 12 console.log(bar); // 5 !

// 関数の引数での rest element function foo([x, ...xs]) {}

http://wiki.ecmascript.org/doku.php?id=harmony:destructuring

Page 27: JavaScript (ECMAScript) 2013

default & rest parameter

モダンな言語では当然の機能 だが Firefox 以外は未サポート

default parameter 引数のデフォルト値を設定

rest parameter 残りの引数を配列で受け取る

Page 28: JavaScript (ECMAScript) 2013

default parameter

e = document.body; // 何か適当な要素 function setBackgroundColor(element, color='orange') { element.style.backgroundColor = color; } setBackgroundColor(e); // オレンジに setBackgroundColor(e, 'blue'); // 青に setBackgroundColor(e, undefined); // オレンジに !

// デフォルト値は呼び出し毎に生成される // 同一オブジェクトが渡される Python などとは違う function getObject(o={}) { return o; } getObject() == getObject() // -> false

http://wiki.ecmascript.org/doku.php?id=harmony:parameter_default_values

Page 29: JavaScript (ECMAScript) 2013

rest parameter

function f(a, b, ...args) { return args; } f("IE", "Chrome"); // -> [] f("IE", "Chrome", "Firefox"); // -> ["Firefox"] !

// rest arguments は Array のメソッドが使える // [].slice.call(arguments) ハックとか不要に function sortRestArgs(...args) {   var sortedArgs = args.sort();   return sortedArgs; }

http://wiki.ecmascript.org/doku.php?id=harmony:rest_parameters

Page 30: JavaScript (ECMAScript) 2013

!

配列の内包表記 (Comprehensions)

配列の内包表記 Python や Haskell にもあるやつ

最近構文変わったので注意! Firefox 2~12 は JS1.7 の構文 Firefox 13~ は旧 ES6 仕様 2013.01 に変更された (RTL→LTR)最新 ES6 構文の実装はまだない

http://wiki.ecmascript.org/doku.php?id=harmony:array_comprehensions

Page 31: JavaScript (ECMAScript) 2013

配列の内包表記 (Comprehensions)

// 配列のフィルタとマップ [for (x of [1,-4,5,3,-7]) if (x > 0) x] // -> [1, 5, 3] // ES5 なら次のように書く // [1,-4,5,3,-7].filter(function(x) { return x > 0 }); [for (x of [2,4,6]) x*x] // -> [4, 16, 36] // ES5 なら次のように書く: // [2,4,6].map(function (x) { return x*xi }); !

// 配列のデカルト積やラベル生成もシンプルに [for (i of [0,2,4]) for (j of [5,3]) i*j] // -> [0, 0, 10, 6, 20, 12] [for (x of 'abc'.split('')) for (y of '123'.split('')) (x+y)]; // -> ["a1","a2","a3","b1","b2","b3","c1","c2","c3"]

Page 32: JavaScript (ECMAScript) 2013

配列の内包表記の構文変更

// 旧 ES6 構文 (現行 Firefox の実装) // 値の定義が最初 (for や if の左) return [a+b for (a of A) for (b of B) if (a > b)] !

// 新 ES6 構文 // 値の定義は最後 (for や if の右) return [for (a of A) for (b of B) if (a > b) a+b] !

// 新構文の方が読みやすいので構文変更された

https://gist.github.com/dherman/b250d1fad15dbb5f77a5

Page 33: JavaScript (ECMAScript) 2013

Modularity

Page 34: JavaScript (ECMAScript) 2013

ブロックスコープ (let, const)

ブロックスコープ変数と定数 IE11 でもサポート! Safari は const でも変数になる const は仕様では let 同様ブロックスコープの定数だが現在の実装は var 同様のブロックスコープ

Page 35: JavaScript (ECMAScript) 2013

let

{ // let 定義: ブロックスコープ let a = 1, b = 10; // let 式・文: let (...) に続く式・文中だけで有効 let (a = 100, c = 300) console.log(a); // -> 100 // for 文などでの let for (let a=0; a<3; a++) { console.log(a+b); // -> 10, 11, 12 } console.log(a); // -> 1 } console.log(a); // × ReferenceError: a is not // defined

Page 36: JavaScript (ECMAScript) 2013

const

// 不変定数を定義 const browser = "Firefox"; !

// 再定義は TypeError となる const browser = "Internet Explorer"; // TypeError: redeclaration of const browser !

// 定数への代入は単に無視される browser = "Chrome"; console.log(browser); // -> "Firefox"

Page 37: JavaScript (ECMAScript) 2013

Class

待望の Class です プロトタイプベース OOP の記法に馴染めない貴方もこれで安心

Page 38: JavaScript (ECMAScript) 2013

Class の利用例

// クラスベース OOP でよく見る感じ class Animal { constructor(name) { this.name = name; this.hungry = true; } eat() { this.hungry = false; } run() { this.hungry = trye; } }

Page 39: JavaScript (ECMAScript) 2013

Class - extends

// 派生クラスの定義がシンプル class LesserPanda extends Animal { constructor(name, tail) { super(name); this.tail = tail; } }

Page 40: JavaScript (ECMAScript) 2013

参考: EcmaScript 5th の場合

// プロトタイプベース function Animal(name) { this.name = name; this.hungry = true; } Animal.prototype.eat = function() { this.hungry = false; } Animal.prototype.run = function() { this.hungry = true; }

Page 41: JavaScript (ECMAScript) 2013

参考: ECMAScript 5th で派生

// プロトタイプベースでの派生は少し気持ち悪い function LesserPanda(name, tail) { Animal.call(this, name); this.tail = tail; } LesserPanda.prototype = Object.create(Animal.prototype); LesserPanda.prototype.constructor = LesserPanda;

Page 42: JavaScript (ECMAScript) 2013

Module

ライブラリの import/export 遂に標準機能に! まだブラウザでは未実装なので es6-module-loader などの変換ツールで処理するしかない…

http://wiki.ecmascript.org/doku.php?id=harmony:modules

Page 43: JavaScript (ECMAScript) 2013

Module

module 'math' { export function sum(x, y) { return x + y; } export var hbar = 1.054571726e-34; // ディラック定数 }

import {sum, hbar} from 'math'; alert("2ℏ = " + sum(hbar, hbar)); // オブジェクトのプロパティに読み込み module Math from 'math'; alert("2ℏ = " + Math.sum(Math.hbar, Math.hbar));

Page 44: JavaScript (ECMAScript) 2013

module import いろいろ

// module のデフォルト export を読み込み import $ from "jquery"; // 変数のプロパティに読み込み module crypto from "crypto"; // 変数に読み込み import { encrypt, decrypt } from "crypto"; // 別名で読み込み import { encrypt as enc } from "crypto"; // 他のモジュールを読み込んで再 export export * from "crypto"; // 他のモジュールから一部だけ再 export export { foo, bar } from "crypto";

http://wiki.ecmascript.org/doku.php?id=harmony:modules

Page 45: JavaScript (ECMAScript) 2013

Readable Code

Page 46: JavaScript (ECMAScript) 2013

Arrow Function

コールバックに便利な関数 シンプルに書ける 矢印なんか格好いい 内外で this が固定される

Firefox 22~ 実装

http://d.hatena.ne.jp/teramako/20130321/p1

Page 47: JavaScript (ECMAScript) 2013

Arrow Function

// return するだけのコールバックがシンプルに [1,2,3].map(x => x * x); // ES5 ではこう書く必要があった: // [1,2,3].map(function (x) { return x * x; }); !

// 引数が 1 つ以外の場合は引数を () で括る setInterval(() => { alert("HEY! 提督ぅー!alertしてもイイけどサー、時間と場所をわきまえなヨー!"); }, Math.random()*10*1000); !

// n! (nの階乗) を求める関数もシンプルに var factorial=((f=n=>n>1 ?n*f(n-1):1)=>(f))(); factorial(10); // 3628800

http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax

Page 48: JavaScript (ECMAScript) 2013

Arrow Function における this

// this は矢印関数を囲むスコープのものにバインド // コールバック利用時に self=this とか不要になる function Person(){ this.age = 0; setInterval(() => { this.age++; // this は Person オブジェクト }, 1000); } var p = new Person(); !

// 注: strict mode でも this はレキシカルに bind // 済みとして振る舞うので undefined にならない

https://developer.mozilla.org/docs/Web/JavaScript/Reference/arrow_functions

Page 49: JavaScript (ECMAScript) 2013

Generator

Python のジェネレータから Firefox が最初に実装 現行仕様とは構文が異なる

最近 V8 が一部実装 最新仕様で動きます

http://wiki.ecmascript.org/doku.php?id=harmony:generators

Page 50: JavaScript (ECMAScript) 2013

Generator 用語

イテレータ (iterator) {value, done} を返す next メソッドを持つオブジェクト

ジェネレータ (generator) ジェネレータ関数で挙動を定義・生成されているイテレータ

ジェネレータ関数 ジェネレータを生成する特殊な関数 yield で next で返す value を指定

http://domenic.me/2013/09/06/es6-iterators-generators-and-iterables/

Page 51: JavaScript (ECMAScript) 2013

Generator を使ったループ処理

// ジェネレータ関数 (ジェネレータのコンストラクタ) function* fibonacci() { let [prev, curr] = [0, 1]; for (;;) { [prev, curr] = [curr, prev + curr]; yield curr; // 値を返して一時停止 } } for (n of fibonacci()) { if (n > 20) break; console.log(n); // 順に 1, 2, 3, 5, 8, 13 }

Page 52: JavaScript (ECMAScript) 2013

Iterator としての Generator

function* counterGenerator() { let c = 0; for (;;) { yield c++; // 値を返して一時停止 } } // ジェネレータを生成 let counter = counterGenerator(); // next() メソッドで {value, done} を得る counter.next(); // -> {value: 0, done: false} counter.next(); // -> {value: 2, done: false} counter.next().value; // -> 2 counter.next().value; // -> 3

補足: Generator を複数生成したらそれぞれ独立してカウントできます

Page 53: JavaScript (ECMAScript) 2013

Promise

非同期処理を綺麗に さらばコールバック地獄 deferred よりも綺麗

Firefox や V8 で実装 今日の基調講演で及川さんも紹介していましたよね!

Page 54: JavaScript (ECMAScript) 2013

Promise で非同期処理

let p = new Promise(function (resolve, reject) { // 3 秒後に resolve 呼んでプロミスが解決する setTimeout(resolve, 3000); }); !

// 解決した (resolve が呼ばれた) ときに実行: p.then(function () { alert('3 秒たったよ!'); }).then(function () { // 解決済みなので即ここも実行される alert('既に 3 秒過ぎてるよ!'); });

詳しい日本語解説: http://js-next.hatenablog.com/entry/2013/11/28/093230

Page 55: JavaScript (ECMAScript) 2013

Promise で引数を使う

let p = new Promise(function (resolve, reject) { // 60 秒後にこのプロミスは解決する // resolve の引数に "60 秒!" を渡す setTimeout(resolve, 60*1000, "60 秒!"); }); !

// resolve の引数を受け取って使う p.then(function (message) { alert(message); // -> "60 秒!" と表示される })

Page 56: JavaScript (ECMAScript) 2013

Promise でエラーハンドリング

p = new Promise(function (resolve, reject) { dream(); // 未定義の関数を呼ぶ (エラー発生) }) !

// エラー発生時は then をスキップして catch へ p.then(function (message) { // p は解決しないのでこのブロックは実行されない alert(message); }).catch(function (error) { // p でエラーが発生するのでこのブロックを実行 alert(error); // -> ReferenceError: dream is not defined });

Page 57: JavaScript (ECMAScript) 2013

Promise のチェイン// s 秒後に解決して resolve に s を渡す Promise を作って返す関数 function wait(s) { var p = new Promise(function (resolve) { setTimeout(resolve, s*1000, s) }); return p; // Promise を返す } // ログを吐いてから s を返す function log(s) { console.log("さっきから "+s+" 秒過ぎたよ") return s; // then で呼ばれたときは Promise にキャストされる } // wait 呼ぶ度に未解決の新しい Promise ができる // 5 秒ごとに 3 回 log が呼ばれる wait(5).then(log).then(wait) .then(log).then(wait) .then(log);

Page 58: JavaScript (ECMAScript) 2013

XHR に Promise を使うfunction ajax(url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest xhr.open('GET', url) xhr.onload = function () { if (xhr.status == 200) { resolve(xhr.response); // 成功時に解決 } else { reject(new Error(xhr.statusText)); // 404 などでリジェクト } } xhr.onerror = reject; // その他のエラー xhr.send(); }) } function onsuccess(response) { alert("成功: "+response); } function onerror(error) { alert("エラー: "+error); } ajax(url).then(onsuccess).catch(onerror)

http://js-next.hatenablog.com/entry/2013/11/28/093230

Page 59: JavaScript (ECMAScript) 2013

New Type & API

Page 60: JavaScript (ECMAScript) 2013

Collections

Simple Set & Map Python: set, dictRuby: Set, HashJava: java.util.HashSet, java.util.HashMap C++: std::unordered_set std::unordered_map

WeakMap & WeakSet 弱参照バージョン (割愛)

Page 61: JavaScript (ECMAScript) 2013

Simple Set

var set = new Set(); // 集合に追加・確認・削除 set.add("Firefox"); set.add("Thunderbird"); set.add(+0); set.add(NaN); set.has("Firefox"); // -> true set.has("Sunbird"); // -> false set.delete("Firefox"); set.has("Firefox"); // -> false // -0 と +0 は区別される, NaN は区別されない set.has(-0);  // -> false   set.has(NaN);  // -> true

JavaScript は内部的には -0 と +0 が異なるからです

Page 62: JavaScript (ECMAScript) 2013

Simple Map

var map = new Map();   var str = "Mozilla", obj = {}, func = function(){}; // Map に値を格納 map.set(str, "Firefox");   map.set(obj, "Thunderbird");   map.set(func, "Japan");   // キーに対応する値を取得 map.get(str);  // -> "Firefox" map.get(obj);  // -> "Thunderbird" map.get(func); // -> "Japan" // 設定したキーと引数の比較は == ではないので注意 map.get("Mozilla");  // -> "Firefox" map.get({});         // -> undefined map.get(function(){}) // -> undefined

キーと引数の比較は === 演算子に近いが厳密には === とも異なる

Page 63: JavaScript (ECMAScript) 2013

API Improvement (割愛)

String の拡張 startsWith, endsWith, contains, repeat, fromCodePoint ...

Number の拡張 isFinite, isNaN, isInteger...

Math の拡張 cosh, sinh, tanh, arosh, asinh, atanh, log1p, log2, log10, sign ...

Page 64: JavaScript (ECMAScript) 2013

Slow Parts & Fast Parts

Page 65: JavaScript (ECMAScript) 2013

Note: JavaScript Good Parts

人間が誤認しにくいコード 意図せぬ挙動を防げる記法 (コーディング規約) を論理的に解説

Douglas Crockford 提唱 JSON の生みの親、JS 業界の重鎮 ECMAScript 4th を葬った人です 職業: The Boss of You

Page 66: JavaScript (ECMAScript) 2013

JavaScript が遅い原因

インタープリタ実行 JIT が有効にならないと超遅い

動的型付け言語 型推論が働かないとかなり遅い

クラスと配列が存在しない Array は Object の派生

数値の型が Number しかない2009 年にも書いた: http://www.slideshare.net/dynamis/trace-monkey

Page 67: JavaScript (ECMAScript) 2013

JavaScript Slow Parts

変数の型を変更 型推論による最適化ができない 遅い原因を克服するエンジンの努力を無に帰すコードの書き方です

プロトタイプチェイン グローバル変数遅い Shape 変わると遅い

エンジンが最適化に苦労するコードの書き方 "Slow Parts" もあれば

Page 68: JavaScript (ECMAScript) 2013

JavaScript Fast Parts

高速処理可能なコード 変数型やオブジェクトの Shape が一定 (型推論で固定型演算可能) 遅い原因を克服して最適化可能になっているコードパターンがある

高速処理可能な機能 Typed Array

エンジンが最適化できる書き方や高速化のための機能 ”Fast Parts" もある

Page 69: JavaScript (ECMAScript) 2013

Typed Array

型固定配列で高速数値演算 元々 WebGL で導入され FileAPI, XHR2, WebSocket などでも採用 分離して ECMA6th にも入った

IE9 非サポートに注意 shim はいろいろある https://github.com/jDataView/jDataView https://bitbucket.org/lindenlab/llsd/src/default/js/typedarray.js

http://www.khronos.org/registry/typedarray/specs/latest/

Page 70: JavaScript (ECMAScript) 2013

ArrayBuffer & View

ArrayBuffer(byteLength) メモリを確保するバッファ

The Typed Array View Types: ArrayBuffer 読み出し用ビュー Int8Array, Unit8Array,Int16Array, Uint16Array,Int32Array, Uinit32Array,Float32Array, Float64Array

Page 71: JavaScript (ECMAScript) 2013

Typed Array

// 16 バイト長のバッファを確保 var buffer = new ArrayBuffer(16); // 32bit 整数 x 4 として読み出すビューを定義 var int32View = new Int32Array(buffer); // 32bit 整数として 0, 2, 4, 6 を格納 for (var i=0; i<int32View.length; i++) { int32View[i]=i*2; } // 16bit 整数 x 8 として同じバッファを読み出すビュー var int16View = new Int16Array(buffer); // 実際に読み出してみる for (var i=0; i<int16View.length; i++) {     console.log(int16View[i]);   }   // -> 0, 0, 2, 0, 4, 0, 6, 0

https://developer.mozilla.org/docs/Web/JavaScript/Typed_arrays

Page 72: JavaScript (ECMAScript) 2013

asm.js

Page 73: JavaScript (ECMAScript) 2013

asm.js とは

JavaScript のサブセット仕様 既存 JavaScript エンジンで動作 高度に最適化可能なパターン

静的型で事前コンパイル可能 経験的に JIT する必要が無い形式

全体または関数単位で有効化 "use asm" とファイルまたは関数の冒頭に記載する

"Fast Parts" (の更に一部) を明文化・定義したもの http://asmjs.org/

Page 74: JavaScript (ECMAScript) 2013

asm.js の設計思想

演算結果を固定型に 型の明示 (Annotation) も既存 JavaScript の範囲内で行う

TypedArray でメモリ管理 ガーベジコレクションを回避

機械生成が前提の設計 C 言語などから変換する対象

C 言語に追いつくための設計 http://asmjs.org/

Page 75: JavaScript (ECMAScript) 2013

asm.js がもたらすもの

Web を Native の速度に CrankShaft や IonMonkey の SSA 最適化 JIT の効果を確実かつオーバーヘッドなく使えるように

予測可能なパフォーマンス 暗黙知 (ダーティハック) にお別れ ams.js 形式で書けば必ず十分に高速化されることが保証される 予測不能な JIT/GC を回避

"Fast Parts" である ams.js なら確実に速く http://asmjs.org/

Page 76: JavaScript (ECMAScript) 2013

大規模アプリは遅かった

大規模アプリの処理速度では C 言語が圧倒的に速い (小規模アプリや一部ベンチ限定で以前から高速)

2013/03 - http://kripken.github.io/mloc_emscripten_talk/#/19

Page 77: JavaScript (ECMAScript) 2013

C 言語に迫る高速化 (asm.js)

asm.js 導入直後で既に C の 2 倍遅い程度まで (Java や C# の処理速度と同程度以上の水準に)

2013/03 - http://kripken.github.io/mloc_emscripten_talk/#/19

Page 78: JavaScript (ECMAScript) 2013

C 言語に迫る高速化 (asm.js)

asm.js 形式の JavaScript コード実行速度は C 言語より数割遅い程度まで迫りまだ高速化中

2013/09 - http://kripken.github.io/mloc_emscripten_talk/sloop.html#/7

Page 79: JavaScript (ECMAScript) 2013

実レベル: Box2D 物理演算エンジン

Box2D では C 言語の 2 倍遅い程度の速度 !

Chrome や IE でも通常の JS より asm.js が高速 Box2DWeb のコードが悪いって話を差し引いても十分

!

Java や CrossBridge (Flash C++ Compiler) と同等以上

2013/07 - http://kripken.github.io/mloc_emscripten_talk/sloop.html#/8

Page 80: JavaScript (ECMAScript) 2013

実用例: Unreal Engine 3

100 万行以上の C & OpenGL コードを 4~5 日で移植 LLVM + Emscripten で JavaScript (asm.js) に変換

epic CITADEL http://www.unrealengine.com/html5/

Page 81: JavaScript (ECMAScript) 2013

日経コミュニケーション 201306 への寄稿原稿から引用

Page 82: JavaScript (ECMAScript) 2013

asm.js にまつわる誤解

機械生成なんてナンセンス CoffeeScript や TypeScript どころか 2006 年には GWT 出てる

特定パターンだけ高速は反則 ベンチを中心に特定パターンへの最適化が積み重ねられてます Emscripten などの機械生成コード利用も広がっておりいずれにしても最適化対象となるパターン

http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html

!?

Page 83: JavaScript (ECMAScript) 2013

asm.js にまつわる誤解

x = x|0 とか非対応だと重い 既存エンジンが既に最適化していたパターン (SunSpider crypto 等) 高速実行可能なコード生成を行っていたツールからできた規則

特殊な JIT エンジンが必要 既存エンジンの簡単な拡張 Firefox では 3 人月、Chrome も数ヶ月で最適化対応を進めた

http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html

!?

Page 84: JavaScript (ECMAScript) 2013

asm.js にまつわる誤解

asm.js は新しい技術 高速コード生成対象パターン 既存の最適化 JIT (CrankShaft や IonMonkey) でコンパイルされる

asm.js は新しい仕様 JavaScript のサブセット固定型は TypedArray で定義済み Emscripten 実行速度は Mozilla だけ有利とならず透明性を高めるため

http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html

!?

Page 85: JavaScript (ECMAScript) 2013

asm.js にまつわる誤解

"use asm" での AOT は反則 型の変わらないコードに対しては元々原理的には AOT 可能 (だが大変) 機械生成で AOT 可能と保証できるなら経験則で判別する必要ない

ES6 の Math.imul に依存してる 32bit 整数演算を行う関数 (後述) 影響は限定的だし Polyfill あります asm.js 専用で生まれた訳じゃない

http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html

!?

Page 86: JavaScript (ECMAScript) 2013

asm.js にまつわる誤解

PNaCl との一騎打ち C++ で書いたコードを高速に Web で動かすという目的は一緒 HTML5 同様に既存 JS との互換性を重視したアプローチが asm.js PNaCl の成否に依らず JS の一部である asm.js への最適化は続く

http://mozakai.blogspot.jp/2013/06/what-asmjs-is-and-what-asmjs-isnt.html

!?

Page 87: JavaScript (ECMAScript) 2013

参考: C to JS コンパイラ比較

http://mozakai.blogspot.co.uk/2013/11/c-to-javascript-emscripten-mandreel-and.html

Emscripten Mandreel Duetto

ライセンス OSS プロプラ 一部プロプラ

アーキテクチャ LLVM IR LLVM tblgen LLVM IR

メモリモデル TypedArray TypedArray JS Object

C/C++ 互換性 フル フル 部分的

関数呼び出し JS ネイティブ TypedArrayをスタックに JS ネイティブ

API C (SDL etc) カスタム HTML5 ベース

その他 Mozilla 製 JS 以外にも変換可能 Server-Clients

Page 88: JavaScript (ECMAScript) 2013

Faster JavaScript

Page 89: JavaScript (ECMAScript) 2013

asm.js がまだ C より遅い理由

コンパイルタイム 避けられないオーバーヘッド 別スレッドで AOT したりキャッシュしたりして解決していく

単精度演算ができない 元々 JavaScript は倍精度のみ

SIMD 命令が使えない 4 データ同時処理で 300% 高速化

Page 90: JavaScript (ECMAScript) 2013

Math.fround

引数を単精度に丸める 単精度演算の明示に利用 明示なしでもエンジンが判断する・できる場合もあるが限定的

SM, JSC, v8 で実装済み

https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/fround

Page 91: JavaScript (ECMAScript) 2013

Math.fround で単精度演算

// 精度によって結果は異なる (1024+0.0001)+1024 // 単精度では 2048 !

// 単精度演算と結果が異なる可能性があるので // 一旦倍精度に変換・演算してから単精度に変換 var f32 = new Float32Array(1000); for (var i = 0; i < 1000; ++i) f32[i] = (f32[i] + f32[i+1]) + 1; !

// Math.fround で明示されれば単精度で実行 var f32 = new Float32Array(1000); for (var i = 0; i < 1000; ++i) f32[i] = Math.fround(f32[i] + f32[i+1]) + 1;

https://blog.mozilla.org/javascript/2013/11/07/efficient-float32-arithmetic-in-javascript/

Page 92: JavaScript (ECMAScript) 2013

単精度演算命令が無いと遅い

倍精度の方が重い CPU あり float32/float64 の相互変換 float32 を倍精度演算するには変換オーバーヘッドが発生

倍精度の方がメモリを消費 メモリ関連処理時間に影響

単精度なら可能な最適化も 数値演算によっては最適化可能

例えば x = 1024, y = 0.0001, z = 1024, (x+y)+z の結果は精度によって異なる

Page 93: JavaScript (ECMAScript) 2013

Math.fround による高速化

Math.fround の導入によって数値演算 ライブラリの速度が最大 60% 高速化

https://blog.mozilla.org/javascript/2013/11/07/efficient-float32-arithmetic-in-javascript/

0%

15%

30%

45%

60%

Matrix Inversions Matrix Graphics Exponential Fast Fourier Transfrom

Desktop (x86) Nexus 10 Nexus 4 Galaxy S3

Page 94: JavaScript (ECMAScript) 2013

Math.imul

C 同様の 32bit 整数の掛け算 これも高速化を助ける関数 これを使わないとエンジンで常に最適化できるとは限らない

https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/imul

Page 95: JavaScript (ECMAScript) 2013

SIMD Module

128bit SIMD モジュール TypedArray の拡張 対応データ型 float32x4, uint32x4

配列とビュー Float32x4Array, Int32x4Array 既存 TypedArray のビューにも

Intel, Google, Mozilla が積極的に取り組んでいるところ

Page 96: JavaScript (ECMAScript) 2013

SIMD 命令が存在しないと遅い

複数データの並列同時計算 CPU 1 クロックで複数データ処理 同時に扱える数倍だけ速くなる

IA32/X64 の MMX/SSE など ARMv7 の NEON など CPU フル活用したいよね!

http://wiki.ecmascript.org/doku.php?id=strawman:simd_number

Page 97: JavaScript (ECMAScript) 2013

SIMD 命令の導入

// 4 つの数値を格納する TypedArray を宣言 var a = float32x4(1.0, 2.0, 3.0, 4.0); var b = float32x4(5.0, 6.0, 7.0, 8.0); !

// 型毎に決まった SIMD 命令で計算実行 var c = SIMD.float32x4.add(a,b); // -> [6.0, 8.0, 10.0, 12.0] // エンジンが最適化で SIMD 使う形に変換できない // 場合に比べてこの計算は 4 倍 (300%) 高速化

https://github.com/johnmccutchan/ecmascript_simd

Page 98: JavaScript (ECMAScript) 2013

Conclusion

Page 99: JavaScript (ECMAScript) 2013

Conclusion

ステキな新機能一杯 コード量もバグも少なく 大規模開発にも対応可能に 書いてて楽しい言語に!

どんどん高速化が進む JavaScript Fast Parts が増える C 言語に迫る高速化が進行中

JavaScript はこれまで通り不可能と言われた壁を乗り越え続けていく…

Page 100: JavaScript (ECMAScript) 2013

Always bet on JavaScript!