JavaScriptのfetchで読み込み遅延やタイムアウトを実装する方法

fetchとは

リクエストやレスポンスといったプロトコルを操作する要素にアクセスするためのJavaScriptインターフェイスです。

よく使われる用途はJSONの取得で、以下のようなコードで簡単にJSONを取得できます。

fetch('https://dummyjson.com/products/1')
  .then((response) => response.json())
  .then((data) => console.log(data))

jQueryの場合は以下のようになります。

$.ajax('https://dummyjson.com/products/1')
  .done((data) => console.log(data))

jQueryはtimeoutオプションでタイムアウトをミリ秒単位で設定すれば、例えば5秒以内にデータが返らなければエラーを出すことが簡単にできます。

$.ajax('https://dummyjson.com/products/1', {
  timeout: 5000
}).done((data) => console.log(data))

しかし、fetchにはtimeoutオプションはないので、タイムアウト処理を別途作成する必要があります。

読み込み遅延表示はsetTimeoutを使う

fetchの読み込み遅延表示はsetTimeoutを使います。

例えば3秒後に表示させる場合は以下のようになります。

fetch('https://dummyjson.com/products/1')
  .then((response) => response.json())
  .then((data) => {
    setTimeout(() => {
      console.log(data)
    }, 3000)
  })

AbortController()でタイムアウトを実装

タイムアウトの実装はAbortController()を使います。

コードは以下の通り。

<button onclick="getProductJSON()">getProductJSON()</button>
<pre id="result"></pre>
async function getProductJSON() {
  const controller = new AbortController()
  const result = document.getElementById('result')
  result.textContent = 'loading...'
  await setTimeout(() => controller.abort(), 10000)

  try {
    const res = await fetch(`https://dummyjson.com/products/1`, {
      signal: controller.signal
    })
    const json = await res.json()
    await new Promise(p => setTimeout(p, 3000))

    if (res.ok) {
      result.innerHTML = JSON.stringify(json, null, '  ')
    } else {
      result.textContent = json
    }
  } catch(e) {
    if (e.name === 'AbortError') {
      result.textContent = 'タイムアウトエラー'
    } else {
      result.textContent = 'ネットワークエラー'
    }
  }
}

fetchでタイムアウト処理を実装したサンプル (10000ms版)

コードの仕様は以下の通り。

  • サンプルページで処理が確認できるようにボタンを押してJSONを読み込む形の処理にしています。
  • awaitを使うので3秒遅延のsetTimeoutもawait new Promiseで処理しています。
  • new AbortController (controller)はfetchの第2引数に { signal: controller.signal }) を指定すれば受け取れます。
  • AbortErrorはtry…catch文で e.name === 'AbortError' で判定できます。
  • 上記のサンプルではタイムアウトの時間を10秒(10000ms)にしてあるので、オフラインでなければJSONを取得できます。

タイムアウト時間を10ミリ秒にしたサンプルも作成したので比べて見てください。

10ミリ秒以内に読み込むことは通常の環境では不可能なので、以下のサンプルでは必ず失敗します。

fetchでタイムアウト処理を実装したサンプル (10ms版)