JavaScript
Ajax
XMLHttpRequest

【メモ】XMLHttpRequestのイベントについて


この記事について

XMLHttpRequest(以下、XHR)のイベントの仕様って、そういえばきちんと把握してないなと思ったので少し調べてみました

その結果をつらつらと書いていきます


通信の終了/成功or失敗の調べ方

本題のイベントに入る前におさらいです

後々必要になります


readyState

xhr.readyStateは以下のいずれかの値を持ちます


定数
状態

0
UNSENT
XHRオブジェクトの作成直後

1
OPENED

open()メソッドの呼び出し後

2
HEADERS_RECEIVED
レスポンスヘッダの受信後

3
LOADING
レスポンスボディを受信中(繰り返し実行される)

4
DONE
XHR通信の完了後

readyStateが4なら通信終了です


status

レスポンスのHTTPステータスです

readyStateが2以上の時アクセス可能で、4になった時に最終的な値が確定します

0なら通信に失敗、0以外なら通信に成功したことを表します

ただし、statusが0以外であってもサーバーへのリクエストが成功したとは限りません(404, 500など)


XHRのイベント

XHRが通信中に起こすイベントは以下の8個


  • onreadystatechange

  • onloadstart

  • onprogress

  • onloadend

  • onload

  • onerror

  • onabort

  • ontimeout


onreadystatechange

もっとも古くから存在する(?)イベントです

readyStateの値が更新されるたびに呼び出されます


onloadstart

open()メソッドが呼ばれたタイミングで呼び出されます

つまり、下の二つは同じです

xhr.onloadstart = function() {

// do something
}

xhr.onreadystatechange = function() {

if(xhr.readyState === 1) {
// do something
}
}


onprogress

レスポンスボディの受信中に繰り返し呼び出されます

つまり、下の二つは同じです

xhr.progress = function() {

// do something
}

xhr.onreadystatechange = function() {

if(xhr.readyState === 3) {
// do something
}
}


onloadend

受信が終了した時に呼び出されます

onloadendは受信の成功or失敗に関わらず呼び出されるので、後述するonloadonerrorを合わせたものだとも言えます

つまり、以下の3つは同じです

xhr.onloadend = function() {

// do something
}

xhr.onload = function() {

// do something
}
xhr.onerror = function() {
// do something
}

xhr.onreadystatechange = function() {

if(xhr.readyState === 4) {
// do something
}
}


onload

受信が成功した時に呼び出されます

つまり、以下の2つは同じです

xhr.onload = function() {

// do something
}

xhr.onreadystatechange = function() {

if(xhr.readyState === 4 && xhr.status !== 0) {
// do something
}
}


onerror

受信が失敗した時に呼び出されます

つまり、以下の2つは同じです

xhr.onerror = function() {

// do something
}

xhr.onreadystatechange = function() {

if(xhr.readyState === 4 && xhr.status === 0) {
// do something
}
}


onabort

通信がabort()メソッドによって中断された場合に呼び出されます

これはonreadystatechangeでは代用できません


ontimeout

接続がタイムアウトした場合に呼び出されます

一応、setTimeoutやらを使えばreadystatechangeで代用は可能ですが割愛します


その他

以下の4つのイベントは同時に発火することがありません


  • onload

  • onerror

  • onabort

  • ontimeout

よって、4つ全て指定しないと通信の終了を取りこぼす可能性があります

ちなみに、それぞれのイベントでのreadyStatestatusは以下のようになります

イベント
readyState
status

onload
4
0以外(レスポンスによる)

onerror
4
0

onabort
通信の進行度による
0

ontimeout
通信の進行度による
0

そもそも、onerrorってどんなときに発火するのかについてですが、例えばXHRのCross-Origin制約に引っかかった場合やネットワーク接続ができない場合など、サーバーとの接続ができなかった場合にerrorとなるようです


まとめ

通信の終了を検知したい場合は, 上記の4つのイベントを見ていれば大丈夫なようです

プログレスバーを実装したい場合は、onprogressを使ってイベントオブジェクトから総バイト数と受信済みバイト数が取得可能なようなので、それで事足りそうです