(2021/08/29 追記)
既に fetch を使っても問題なくなっているので 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失敗に関わらず呼び出されるので、後述するonload
とonerror
を合わせたものだとも言えます
つまり、以下の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つ全て指定しないと通信の終了を取りこぼす可能性があります
ちなみに、それぞれのイベントでのreadyState
とstatus
は以下のようになります
イベント | readyState | status |
---|---|---|
onload | 4 | 0以外(レスポンスによる) |
onerror | 4 | 0 |
onabort | 通信の進行度による | 0 |
ontimeout | 通信の進行度による | 0 |
そもそも、onerror
ってどんなときに発火するのかについてですが、例えばXHRのCross-Origin制約に引っかかった場合やネットワーク接続ができない場合など、サーバーとの接続ができなかった場合にerrorとなるようです
まとめ
通信の終了を検知したい場合は, 上記の4つのイベントを見ていれば大丈夫なようです
プログレスバーを実装したい場合は、onprogress
を使ってイベントオブジェクトから総バイト数と受信済みバイト数が取得可能なようなので、それで事足りそうです