メッセージ

2020年08月22日の記事

2020/08/22(土)javascript の fetch と XMLHttpRequest

今回は、これにちょっと嵌ったので自分メモ。
fetch も XMLHttpRequest も Javascript 内でWebサーバと通信処理が出来る便利な機能で
ちょっと前は「Ajax」とか言ってもてはやされたものですが、今はほぼ死語でしょうかね。
それでも今はWebサイトでちょっとしたことをするには欠かせなくなってきているもの。

今回は、オンラインでの画像編集機能をサイト内にて実現するために、
最初は fetch による以下のコードを書きました(一部を公開用に変更部分あり):
async function gosub_canvasimg(serial,imgblob) {
  var responce = await (await fetch('/editor.cgi', {
                          method : 'POST',
                          cache  : 'no-cache',
                          headers : {'Content-Type' : 'application/x-www-form-urlencoded' } ,
                          body   : 'imgblob=' + imgblob ;
                         })).text() ;
  if (responce != 'valid') {
    alert(serial + "つめの画像ファイル保存に失敗しました。" );
  }
}
ところが、これだと、
Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.
というエラーが出て、fetch 自体が実行されないのです。*1
これは、拙作のシステムにて「画像があるはずだが、編集画面で表示されない」という現象を作り出す直接原因になっていました。

同期処理でないと、編集時に不具合が更に出るので、こうしています。
『同期処理なんぞ殆ど使われません』と大声で叫ぶサイトなんかも散見されますが、
それはよほど精通している方か、同期処理の必要な案件に出会ったことが無い方なのでしょう。
少なくともハードウェアの制御がシステム全体として絡んで来ると、同期処理はどうやっても必須。

結局、fetch がエラーになる原因は判らず仕舞いで、fetch のところを同じ処理になるように、
async function gosub_canvasimg(serial,imgblob) {
  var imgxhr  = new XMLHttpRequest() ;
  var msgbody = 'imgblob=' + imgblob ;

  imgxhr.open('POST', '/editor.cgi', false) ;
  imgxhr.send(msgbody) ;
  var responce = imgxhr.response ;

  if (responce != 'valid') {
    alert(serial + "つめの画像ファイル保存に失敗しました。" );
  }
}
みたいな感じにすると、エラーは出なくなった模様。
これで不具合は出なくなったと思うが様子見です。
fetch の実装バグなのか、「同期方式」という使い方が悪いのか調べても全く判らないのです。

やっぱり XMLHttpRequest() のほうが断然判りやすい。
fetch は Promise という挙動の概念を理解しなければならず、これが当方にはあまり直感的ではなく判りずらさの極みです。これを使いこなせないのがこの顛末の一因でしょう。

何せ、類似の事例が殆ど表に出てきていない案件なので、エンドユーザに動作検証してもらうという暴挙を敢行するしかないのです。

*1 : 当方は英語が苦手なので、日本語表示がある程度出来る Firefox でデバッグをしています. chrome のデバッガは、英語だらけで正直発狂しそうになります...