人生が二度あれば

フロントエンドエンジニア 山岸和利による私的なメモ帖です。JavaScriptを主として、ウェブ周辺技術全般の記事を書いています。

fetch API から XMLHttpRequest への置き換えを決意した話

Jul 21st, 2016

最近 fetch API をヘビーに使うようになっていて、いろいろと勘所もわかってきていて、Promise ベースなのはやっぱりすごく便利なんだけれども、現状だと機能が全然足りないなあ、と。

XMLHttpRequestUpload 相当がないのは知っていたし、困ったなあと思っていたんだけれども、XMLHttpRequestUpload 自体がだいぶレア目のヤツで使うような機会もまあめったにないので実害としてはそこまで大きくなかった。

んで、だ、XMLHttpRequestUpload 相当がないのは良いとしても、ReadableStreamXMLHttpRequest で言う progress イベント相当のことをしようとしたときに、発火時にトータルの容量がわからんつう問題が発生した。

fetch API で ReadableStream を使って progress の状況を取るときは

function consume(reader) {
  var total = 0;
  return (function pump() {
    return reader.read().then(function(args) {
      if (!args.done) {
        total += args.value.byteLength;
        return pump();
      }
    });
  })();
};

fetch('/path/to').then(function(response) {
  var reader = response.body.getReader();
  return consume(reader);
});

といったコードを使う。データを受信するごとに total 変数に、受信したデータのバイト数を追加していくことしかできない。

forbidden headers の中に Content-Length があるからしゃあないちゃしゃあないような気もするんだけれども、どうしたもんかまじでわからん。

トータルの容量がわからんとなにが困るって、進捗の表示ができないんだよ。

xhr.onprogress = function(e) {
  result.textContent = e.loaded / e.total;
};

ていうので XMLHttpRequest だったら一瞬で進捗状況を表示させられていたけど、fetch API だとできない。いや仕様的には [[totalQueuedBytes]] つうのがあるんだけれども internal slot 扱いで JavaScript から取ることはできない。

これ、誰も困っていないのかな。困るよなあ。困るよなあ。どうすんのまじでコレ。

っていうのと今日実装している最中であーってなったのは XMLHttpRequest.abort() 相当のものがないってこと。まじでどうすんだよこれ!!! 今週の土日で今書いているプロダクトで fetch API を使っている箇所を XMLHttpRequest に置き換えるわ。やっぱり世界に fetch API は早かった。XMLHttpRequest ですよ、やっぱり。

XMLHttpRequest 最高!!!

……

という話でおわるのも酷いので補足をしますが、ちゃんと要所を抑えて使うと fetch API は非常に便利です。

Promise ベースというのはイベントベースの API よりもはるかに記述が単純で済みます。コードが煩雑になってしまうのを防ぎますし、この記事を書いている 2016 年 7 月時点では stage 3 の Async Functions (ES 2017 にはいるとうれしいですね) といっしょに使うことによって、コールバックファンクションばかりになってしまうということも避けられます。

今後も Promise ベースの流れが続くのが幸いだと思いつつも、現状の fetch API は「つらいなあ」というお話です。そもそも fetch API は XMLHttpRequest の代替というわけではないので、お門違いも甚しいんですけどね。

fetch API は Living Standard です。今後も改良が続けられていきます。この記事で上げている XMLHttpRequest との差異もいづれ埋められて行くでしょう。わたしはこの記事が陳腐化してしまうことを切に祈っています。

世界がもっと平和になりますように。

Recent Posts

Archive