こんにちわ。開発チームのkoyaです。 今回はどんなネタがいいかなと思っていたところ、Measuring Page Load Speed with Navigation Timingという記事でNavigation TimingというAPIがあることを知りました。 Navigation Timingはウェブアプリケーションのパフォーマンスを計測できるJavaScriptのAPIです。 JavaScriptのAPIなのでCanvasと組み合わせて取得したデータを表現してみたらおもしろいかと思いやってみました。
はじめに、Navigation Timingについて簡単に紹介します(元記事により詳しい情報があるので興味を持たれた方は是非そちらを読んでみてください)。 その後、Canvasを使ってNavigation Timingの情報をグラフ化してみます。
Navigation Timingの利用
Navigation Timingは2つのオブジェクトnavigationとtimingで構成されます(そのままですね)。 それぞれwindow.performanceのプロパティとして提供されます。
- navigation: どのようにページへ遷移してきたかの情報
- timing: ページロード時の時間情報
現在は最新のFirefoxとGoogle Chrome、IE9が対応しています。
ロード時間の取得
それぞれのイベントごとに1970/01/01からの経過時間がミリ秒単位でセットされます。 例えば次のような値です。
- navigationStart: 1320317663113
- redirectStart: 0
- redirectEnd: 0
- fetchStart: 1320317663113
- domainLookupStart: 1320317663113
- domainLookupEnd: 1320317663113
- connectStart: 1320317663113
- connectEnd: 1320317663113
- requestStart: 1320317663114
- responseStart: 1320317663114
- responseEnd: 1320317663115
- domLoading: 1320317663118
- domInteractive: 1320317663315
- domContentLoadedEventStart: 1320317663315
- domContentLoadedEventEnd: 1320317663316
- domComplete: 1320317663316
- loadEventStart: 1320317663316
- loadEventEnd: 1320317663316
値が0の場合はそのイベントが起きなかったなど無効なことを表します。 それぞれの差分をとることでトータルのロード時間やネットワークレイテンシー、リダイレクトにかかった時間などを計算できます。
ページ遷移情報の取得
navigationオブジェクトにはページ遷移に関する2つのプロパティがあります。
- redirectCount: 最終的なドキュメントにたどりつくまで何回リダイレクトされたか
- type: ページへのナビゲーション方法
typeには次のいずれかの値がセットされます。
- TYPE_NAVIGATE(=0): リンクのクリックやアドレスバーへのURL入力、フォームサブミットなど下記タイプ以外のアクション
- TYPE_RELOAD(=1): リロード
- TYPE_BACK_FORWARD(=2): 戻るや進むといったヒストリ操作
Navigation Timingはシンプルですが有益な情報が取得できますね。 元記事ではAjaxを使って直接データを集めたり、localstorageを使って統計情報を作るといったアイディアが紹介されています。
Canvasによる可視化
実際に使ってみた例を示します。データを収集し統計情報を取ったりするのがおもしろいと思いますが、ちょっと難しいので取得したデータを簡単に表示させてみます。 テキストで出すだけではあまり面白くないのでCanvasを使ってみます。
ネットワーク遅延時間
ページロード時間で気になるのは、どのくらい時間がかかったか、そして何に時間がかかったかです。 Navigation Timingのいいところはネットワークのやりとりに使っている時間も取得できるところです。
canvas要素
はじめに幅と高さを指定してcanvas要素を追加します。対応していないブラウザのためのメッセージもセットしておきます。
<canvas width="400" height="300">(キャンバス非対応)</canvas>
ケーキの一切れ
円グラフを作るために扇形(ケーキの一切れ)を描画できるようにします。 基本的な図形描画処理なので後々便利なように2Dコンテキストを拡張します。
CanvasRenderingContext2D.prototype.fillWedge = function (x, y, radius, startAngle, endAngle, anticlockwise) {
// パスをセット
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, startAngle, endAngle, anticlockwise);
this.closePath();
// 塗りつぶし
this.fill();
}
図はanticlockwise(反時計回り)フラグをfalseにした場合ですが、trueをセットすると角度の指定が反時計回りになります。
データの取得
ロード時にデータを表示したいのでonloadイベントで処理したいところですが、 onloadイベント中ではtiming.loadEventEndに値がセットされていません。 ロードをきっかけに処理したい場合はsetTimeout()を使います。 setTimeout()のハンドラではloadEventEndに値がセットされた状態で処理することができます。
window.onload = function() {
setTimeout(function() {
var timing = window.performance.timing; // loadEventEndに値がセット済み!
...
}, 0);
}
円グラフ
準備ができたのでcanvas要素に円グラフを描画します。
window.onload = function() {
setTimeout(function() {
// キャンバスとコンテキストを取得
var canvas = document.getElementsByName("canvas")[0];
var context = canvas.getContext('2d');
// データと色情報を準備
var timing = window.performance.timing;
var data = [timing.navigationStart, timing.responseEnd, timing.loadEventEnd];
var colors = ["#933", "#FCC"];
// 描画位置と半径をセット
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 100;
// 円グラフの描画
drawPie(context, x, y, radius, data, colors);
}, 0);
}
キャンバスとtimingデータを取得してdrawPie()関数で円グラフを描画しています。 drawPie()関数の定義は次のようになります。
function drawPie(context, x, y, radius, data, colors) {
var i, last, startAngle, endAngle;
for (i = 0, last = data.length - 1; i < last; ++i) {
// データを角度にマッピング
startAngle = map(data[i], data[0], data[last], -Math.PI*0.5, Math.PI*1.5);
endAngle = map(data[i+1], data[0], data[last], -Math.PI*0.5, Math.PI*1.5);
context.fillStyle = colors[i];
context.fillWedge(x, y, radius, startAngle, endAngle, false);
}
}
function map(x, low1, high1, low2, high2) {
// low1 < x < high1を[low2, high2]の範囲にマッピング
return (x - low1) * (high2 - low2) / (high1 - low1) + low2;
}
drawPie()関数では開始から終了まで2つの時間データをとり、それぞれ円上の角度に変換して扇形を描いていきます。 map()関数はある範囲にある値を別の範囲にマッピングしています。この場合は時間から角度ですね。
実行すると次のようなグラフが得られます。
トータル時間や凡例を追加したりしたのが次の図になります。
まとめ
Navigation Timingを利用するとユーザー体験よりのパフォーマンス情報が簡単に得られることが分かりました。 また、Canvasを組み合わせてデータをグラフ化してみました。今のところ新しいブラウザでしか対応されてはいませんが、シンプルで扱いやすいためパフォーマンス解析の手段として活用していければと思います。
参考