こんにちは、クラウドSRE部の菅原です。
エンジニアの皆さんはサーバーのレスポンスタイムなどの速度計測を行っていると思いますが、ブラウザ側で要素が描画される時間は計測できておりますでしょうか?
今回は、ブラウザ上で 画面が表示されてから操作可能になるまでの速度 を計測し、Google Analytics で可視化する対応について説明します。
背景
IDCFクラウドの仮想マシン一覧で保有しているVMの数が多いと、JavaScriptの処理が画面を30秒以上ロックしてしまう現象が発生しました。
お客さまの報告から発覚したことですが、「遅い!」というキーワードから連想するのはサーバーのレスポンスタイムという先入観があったので、そのような状況に気づけませんでしたし、フロントエンドの速度を計測していない状態での調査は大変でした。JavaScriptの処理を修正し、遅いという問題は改善しましたが、今後このような事態を分析できるデータが必要だという課題が残りました。
これらを改善したいという思いから、この対応に取り組みました。
計測方法
ブラウザの処理時間を計測するためにJavaScriptのperformance.getEntriesByType()メソッドを使用します。
performance.getEntriesByType('navigation')[0]を実行すると以下のようなデータが取れます。
これらは、ブラウザが検知しているイベント発生時点の経過時間をミリ秒単位で記録したものです。
connectEnd: 10.900000001129229 connectStart: 10.900000001129229 decodedBodySize: 177316 domComplete: 370.43000000267057 domContentLoadedEventEnd: 214.36000000539934 domContentLoadedEventStart: 214.02500000112923 ~ 中略 ~ requestStart: 12.945000002218876 responseEnd: 15.859999999520369 responseStart: 13.275000004796311 ~ 略 ~
画面が表示されてから操作可能になるまでの速度 を、上記の responseEndとdomContentLoadedEventEndを用いて以下のJavaScriptで表現すると、処理時間timeは198(ms)となりました。(小数点以下は切り捨て)
var perform = performance.getEntriesByType('navigation')[0];
var time = Math.floor(perform.domContentLoadedEventEnd - perform.responseEnd);
Google Analytics へ送信する
上記の値は Google Analytics のカスタム速度へ送信することにしました。
以下のような記述で送信することができます。(analytics.js を読み込んでいる前提)
window.addEventListener('load', function () {
try {
// パフォーマンスの情報取得
var perform = performance.getEntriesByType('navigation')[0];
var time = Math.floor(perform.domContentLoadedEventEnd - perform.responseEnd);
// gaのカスタム速度へ値を送信する
ga('send', {
hitType: 'timing',
timingCategory: 'DOMContentLoaded',
timingVar: location.pathname,
timingValue: time,
timingLabel: label
});
} catch (e) {
// 例外処理
}
});
上記データの収集だけでも良いのですが、今回はコネクションの情報も送信するように対応しました。
responseEndからdomContentLoadedEventEndまでの時間にはjs、cssなどのファイルをダウンロードする時間も含まれております。
ユーザーの環境で回線速度が遅かった場合にはjs、cssなどのダウンロード時間が大きくなってしまうため、コネクションの情報も収集することで調査の指標とすることが狙いです。
コネクションの情報は、以下の記述で取得することができます。(Google Chrome のみ)
var connectionInfo = '';
if (navigator.connection) {
var connection = navigator.connection;
connectionInfo = JSON.stringify({
'downlink': connection.downlink,
'effectiveType': connection.effectiveType,
'rtt': connection.rtt,
'saveData': connection.saveData
});
}
コネクションの値はGoogle Analyticsのカスタムディメンションに設定することにしました。
カスタムディメンションは Google Analytics >「管理」>「プロパティ」>「カスタム定義」>「カスタムディメンション」で作成できます。

以下の記述で完成です!
window.addEventListener('load', function () {
try {
// パフォーマンスの情報取得
var perform = performance.getEntriesByType('navigation')[0];
var time = Math.floor(perform.domContentLoadedEventEnd - perform.responseEnd);
var connectionInfo = '';
// コネクションの情報を取得
if (navigator.connection) {
var connection = navigator.connection;
connectionInfo = JSON.stringify({
'downlink': connection.downlink,
'effectiveType': connection.effectiveType,
'rtt': connection.rtt,
'saveData': connection.saveData
});
}
// gaのカスタムディメンションにコネクション情報を設定
ga('set', 'dimension1', connectionInfo);
// gaのカスタム速度へ値を送信する
ga('send', {
hitType: 'timing',
timingCategory: 'DOMContentLoaded',
timingVar: location.pathname,
timingValue: time,
timingLabel: label
});
} catch (e) {
// 例外処理
}
});
Google Analytics では以下のように表示されます。


まとめ
いかがでしょうか?
フロントエンドの速度計測はなかなか奥が深いですよね。
上記の対応で画面が表示されてから操作可能になるまでの速度について分析できるようになり、フロントエンド側の速度低下に気づけるようになりました。
速度だけではなくネットワークコネクションの情報も収集したことで、より分析の精度を高められたと思います。
IDCFクラウドでは、このようなデータを基に今後の改善に役立てていきたいと考えています。
さらに今後はjs、cssファイルのダウンロード時間など、より細かい速度について計測できるような仕組みを考えていけたらと思います!