JavaScript

レシピ

Ajax

XMLHttpRequestによるファイルの読み込み状況を取得する

XMLHttpRequestによるデータ読み込みの途中経過を調べる方法について解説します。

この記事のポイント

  • サーバーから読み込んでいる間はProgressEventオブジェクトloadedプロパティから読み込んだバイト数を取得する
  • ファイルサイズはtotalプロパティを参照する
  • ファイルサイズを取得できるかどうかはlengthComputableプロパティから確認する

Ajaxでサーバーから読み込むファイルの途中経過を取得

XMLHttpRequestオブジェクトによるAjaxを使ってサーバーから特定のファイルを読み込むとき、現在どれだけ読み込んだか調べるときはProgressEventオブジェクトloadedプロパティから取得することができます。

ProgressEventオブジェクトXMLHttpRequestオブジェクトによるサーバーとの通信において、レスポンスデータを受け取っているときに発生します。
このオブジェクトのプロパティはイベントprogressを検出したときに引数として受け取って参照します。

JavaScript コード例

xhr.open('get', './test.mov', true);
xhr.responseType = 'blob';
xhr.send();

xhr.addEventListener('progress',(e) => {

	// 読み込んだバイト数を表示
	console.log(e.loaded);
});

イベントprogressはレスポンスデータを受け取っている間は定期的に発生するため、読み込むファイルのサイズ(容量)が大きいほど繰り返し発生します。
例えば上記のコードで約65.7MBのファイルをサーバーから読み込むと、以下のように現時点で読み込んだバイト数を出力します。

コンソールの出力例

524288
9764864
21168128
30081024
40566784
65665095

ProgressEventオブジェクトには読み込むファイルのサイズが数値で入ったtotalプロパティが用意されています。
totalプロパティloadedプロパティを組み合わせると、現在全体の何%を読み込んだかを調べることができます。

ただし、サーバーによってファイルのサイズを取得できないことがあります。
totalプロパティからファイルサイズを取得できるかどうかはlengthComputableプロパティで確認することができるため、取得できるときとできないときで処理を分岐させることが可能です。

以下の例では、サーバーから「test.mov」というファイルを取得して、読み込みが完了したらid属性file_area」のdiv要素に動画を表示します。
ファイルの読み込み状況はid属性text_loading」のp要素に表示します。

HTML コード例

<article>
	<h1>JavaScriptレシピ</h1>
	<div id="file_area"></div>
	<p id="text_loading"></p>
</article>

JavaScript コード例

// 読み込むファイルのURLを指定して通信開始
xhr.open('get', './test.mov');
xhr.responseType = 'blob';
xhr.send();

// レスポンスデータを受け取っている間は定期的に発生するイベント
xhr.addEventListener('progress', (e) => {

	// p要素に進捗状況を表示
	if( e.lengthComputable ) {
		text_loading.textContent = Math.floor((e.loaded / e.total) * 100) + "%";
	} else {
		text_loading.textContent = "読み込み中";
	}
});

xhr.onreadystatechange = function() {

	// 通信が正常に完了したか確認する
	if( xhr.readyState === 4 && xhr.status === 200) {

		// p要素に読み込み完了を表示
		text_loading.textContent = "読み込み完了";

		// 読み込んだ動画ファイルを表示
		const file_area = document.getElementById("file_area");
		const video_element = document.createElement('video');
		video_element.src = URL.createObjectURL(this.response);
		video_element.controls = true;
		file_area.appendChild(video_element);
	}
};

lengthComputableプロパティはファイルサイズを取得できる場合はtrue、取得できない場合はfalseが入ります。
そこで、上記のようにif文を使ってファイルサイズを取得できたときのみ「読み込んだバイト数 / ファイルサイズ」という計算をして現在の進捗を表示します。

ファイルサイズを取得できなかったときは読み込んでいる間は「読み込み中」と表示して、読み込み完了したときに「読み込み完了」と表示します。

こちらの記事は役に立ちましたか?

ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。

コメントありがとうございます!
運営の参考にさせていただきます。