JavaScript 実践講座 Framework, Tool, Performance taiga.jp Taiga Hirohata
JavaScript 実践講座
Framework, Tool, Performance
taiga.jp Taiga Hirohata
About
Freelance engineer (Flash, Flex, AIR, JavaScript etc)
Principle Classmethod, Inc.
Adobe Community Professional
http://taiga.jp/
@taiga
© 2013 taiga.jp 2 / 54
Practical JavaScript http://tv.adobe.com/watch/max-2013/practical-javascript/
Original
© 2013 taiga.jp 3 / 54
Agenda
Framework
Tools
Performance
© 2013 taiga.jp 4 / 54
当セッションにおける要素
問題 解決策 将来
© 2013 taiga.jp 5 / 54
Frameworks
© 2013 taiga.jp 6 / 54
ブラウザ対応
一貫性のないブラウザ API
Ex : 9 以前の IE は attachEvent() 9 以降は addEventListener() を使用
ブラウザ機能の矛盾
Ex : <input type="data">
© 2013 taiga.jp 7 / 54
JavaScript Libraries
Utility
jQuery(event listeners, XHR, etc.) http://api.jquery.com/category/events/ http://api.jquery.com/Types/#jqXHR
Underscore(collections, etc) http://underscorejs.org/#collections
© 2013 taiga.jp 8 / 54
JavaScript Libraries
Polyfills 古いブラウザでもモダンブラウザと同等の機能を提供
html5shiv / html5shim
selectivizr
es5-shim
Mozilla Developer Network samples
© 2013 taiga.jp 9 / 54
JavaScript Libraries
Feature detection 特徴検出
Moderinizr http://modernizr.com/
YepNope http://yepnopejs.com/
© 2013 taiga.jp 10 / 54
JavaScript Libraries
Ease of library use
Library bundles (HTML5 Boilerplate)
Package managers (Bower)
Scaffolding generators (Yeoman)
© 2013 taiga.jp 11 / 54
非常に積極的にリリースされている
これまで以上に速く近代化している
今まで以上に標準に従っていく
ブラウザの改善
© 2013 taiga.jp 12 / 54
依存関係分かりますか?
本当にすべてのファイル使ってますか?
これらは正しい順序でロードされていますか? <script src="script3.js"></script>
<script src="script1.js"></script>
<script src="script11.js"></script>
<script src="script21.js"></script>
<script src="script30.js"></script>
…
依存関係、スパゲッティ
© 2013 taiga.jp 14 / 54
http://requirejs.org/
Module Pattern
RequireJS Pattern
RequireJS
© 2013 taiga.jp 15 / 54
Logger.js
RequireJS
define(...) { ... function print(msg) {
console.log(msg);
}
// Define public API
exports.print = priint;
});
define(function(require, exports, module) { var Logger = require("pkg/Logger"); function sayHelloWorld() {
Logger.print("Hello, world!");
}
// Define public API
exports.sayHelloWorld = sayHelloWorld;
});
© 2013 taiga.jp 16 / 54
Modules in ES6 Harmony
module "foo" { import "pkgLogger" as Logger; function sayHelloWorld() {
Logger.print("Hello, world!");
}
// Define public API
export sayHelloWorld;
}
© 2013 taiga.jp 17 / 54
非同期プログラムは難しい
コールバックは悪くない …が改善の余地がある
非同期コード
© 2013 taiga.jp 18 / 54
非同期処理完了のリスニング
リスナーにはオブジェクトが返される
Promises
var options = … ; var promise = beginSomeAsyncOperation(options); promise.done(function(result) {
console.log("Operation finishes with result:" + result); }); promise.fail(function(errorCode) {
console.log("Operation failed. Error:" + errorCode); });
© 2013 taiga.jp 19 / 54
内部的に、非同期 API は処理完了後に 遅延オブジェクトを生成して返します
Promises
function beginSomeAsyncOperation(options) { var result = new $.Deffered(); sendNetworkRequest( function(response) {
if(response.error) result.reject(response.error); else result.resolve(response.data); });
return result.promise(); //req still pending here }
© 2013 taiga.jp 20 / 54
「ピラミッド」を回避 Callbacks authenticate(userName, password,
fucntion () { findRecord(itemId,... function(item) {
applyUpdates(item);
saveRecord(item,
function (result) {
indicateSucess();
}
);
}
); }
);
Promise chaining authenticate(userName, password) .then( function() {
return findRecord(itemId);
})
.then( function(item) {
applyUpdates(item);
return saveRecord(item);
})
.then( function(result) {
indicateSucess();
});
© 2013 taiga.jp 21 / 54
ES6 Harmony "yield" Promise chaining
authenticate(userName, password) .then( function() {
return findRecord(itemId);
})
.then( function(item) {
applyUpdates(item);
return saveRecord(item);
})
.then( function(result) {
indicateSucess();
});
ES6 "yield" + task.js spawn(function() {
yield authenticate(userName, password);
var item = yield findRecord(itemId);
applyUpdates(item);
var result = yield saveRecord(item);
indicateSucess();
});
© 2013 taiga.jp 22 / 54
将来は非同期実行のフローを ツールが理解して教えてくれる…はず
より良いデバッギング
© 2013 taiga.jp 23 / 54
手作業によるスパゲッティ化
限定的な UI 更新
$("project-title").text(filename);
$(".dialog .validation-error").toggle(isError);
$(".modal-overlay ul.songs li:eq(" + i + ")").addClass("selected");
dialog.appendChild(document.createElement("div"));
dialog.firstCihld.innerHTML = "<input type='text' value='"
+ htmlEscape(imte.name) + "'>";
$("#help-sidebar .main-content").html(newContent);
© 2013 taiga.jp 24 / 54
View
Underscore
Mustache
Handlebars
Templating & MVC F/W
© 2013 taiga.jp 25 / 54
Model
Backbone
Templating & MVC F/W
© 2013 taiga.jp 26 / 54
Controller
Knockout
Batman
Ember
Angular
Knockback
Templating & MVC F/W
© 2013 taiga.jp 27 / 54
JavaScript F/W Popularity
© 2013 taiga.jp
from GitHub Archive
28 / 54
プレーンなモデルの使用
Ember, Backbone name = model.get("songName");
model.set("rating", 5);
ES5 Getters/Setters
© 2013 taiga.jp 29 / 54
プレーンなモデルの使用
Knockout name = model.songName();
model.rating(5);
ES5 Getters/Setters
© 2013 taiga.jp 30 / 54
プレーンなモデルの使用
Serenade name = model.songName;
model.rating = 5;
ES5 Getters/Setters
© 2013 taiga.jp 31 / 54
Web1.0 アプリは常に C/S 往復
サーバ上のクラッシュ
サーバ上の遅延
モダンアプリはクライアント処理が主流
どのようにクライアント端末上の クラッシュや遅延を知ればよい?
サーバログ
© 2013 taiga.jp 32 / 54
var errors=[]; window.onerror = function(msg, fileUrl, lineNum) { errors.push({msg: msg, file: fileTrl, line: lineNum}); };
setInterval(function() { sendToServer(errors);
errors = [];
}, 5000);
Error Logging
© 2013 taiga.jp 33 / 54
Open bugs in …
WebKit
Chrome
Firefox
フルスタックトレース…?
© 2013 taiga.jp 34 / 54
<html>
<head>
<script>
function onLoad() {
var now = Date.now();
var pageLoadTime = now - pertformance.timing.natigationStart;
sendToServer(pageLoadTime);
}
</script>
</head>
<body onload="onLoad()">
...
Performance APIs
© 2013 taiga.jp 35 / 54
Tools
© 2013 taiga.jp 36 / 54
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]]) [+!+[]+[+[]]]+(![]+[])[+!+[]+!+[]]
シートベルトなし運転
© 2013 taiga.jp 37 / 54
型チェックなし
変数の型が動的に変更可能 凸(゚皿゚メ)
暗黙の型変換
構造化不足
繰り返される決まり文句の表記
シートベルトなし運転
© 2013 taiga.jp 38 / 54
コンパイルなし ≒ IDEの文法チェックなし
Linting は安全性を与える
統合解析 / Linting
© 2013 taiga.jp 39 / 54
統合解析 / Linting
ex :
Brackets Continuous Compilation extension
https://github.com/JoachimK/brackets-continuous-compilation
© 2013 taiga.jp 40 / 54
ヒントを超えた情報
完全にインタラクティブな編集
コンテキスト スニペット
© 2013 taiga.jp 41 / 54
型推論
© 2013 taiga.jp 42 / 54
型推論
© 2013 taiga.jp 43 / 54
型推論
© 2013 taiga.jp 44 / 54
クロスコンパイラ
© 2013 taiga.jp 45 / 54
ソースマップ
© 2013 taiga.jp 46 / 54
履歴デバッグ
振り返りデバッグ
統合的ビュー実行
Code/Test/Debug Cycle 融合
© 2013 taiga.jp 47 / 54
Performance
© 2013 taiga.jp 48 / 54
var start = Date.now(); //... Do do stuff ... var end = Date.now(); console.log((end - start) + "ms"); //CSS style calculation //Layout //Repaint //User sees update->Date.now()==???
評価が難しい
© 2013 taiga.jp 49 / 54
Timeline panel (http://goo.gl/Vim9r)
パフォーマンスツール
© 2013 taiga.jp 50 / 54
Timeline demo (http://goo.gl/1Z7Jp)
パフォーマンスツール
© 2013 taiga.jp 51 / 54
FPS counter (chrome://flags)
パフォーマンスツール
© 2013 taiga.jp 52 / 54
CSS selector profiling
Repaint rectangles
Render layer borders
→ Session Web Dev2
パフォーマンスツール
© 2013 taiga.jp 53 / 54
Resource Timing ページ上の各リソース読み込みタイミング
Async Scroll スクロールのパフォーマンスをテストする
Display Performance フレームレート関連 API
Programmatic APIs
© 2013 taiga.jp 54 / 54