jquery: Tabulator 出来てみた5.555(Ajax making too many requests との格闘とか – AJAX Data Loadingの話の続き)

いやぁ、思ったよりネタが枯れないね。

ほんと、これで Tabulator ネタとしてはおしまいにして、「ほんとにやろうとしてる本題」に行くつもりだったんだよ、けど「AJAX Data Loading」ネタは興味深い話はまだあった。

これでネタとして使っている MyAnimeList.net なんだけどね、これさ、「日本のアニメ」のサイトであるにも関わらず「海外の人向け」(というか英語が読める国の人向け)なので、人名や番組名の日本語名、つまり我々にとったら「正式名称」が「個々の詳細ページを訪問しないと取得出来ない」のよ。まぁ本家としての日本人には使いにくいんだけれど、仕方がないちゃぁ仕方がないのね。

で。これをさ、「日本語名も表に出したいんだよヲラァ」したいならば、テーブルの一行ごとに「別途詳細ページに取りにいく」必要があるのさ。具体例だと、anime/35557/Houseki_no_Kuni_TV/characters からはキャラ名も声優名も英語でしか取れなくて、キャラ名が欲しいなら例えば character/110355/Phosphophyllite、声優名が欲しいなら例えば people/11661/Tomoyo_Kurosawa に改めて情報を取りに行かなければならない。

自分用にはこの後も機能を増やしてはいくけれど、そうすると複雑になりすぎてこうやって「技術の説明」をするのに段々相応しくなくなってくるので、「汎化直前」の状態の今(悪い言い方をするなら「未整理」)を見せとこうと思う:


一個一個説明するのもダルいので、ポイントとなる部分だけ:

 1 var getAsyncDataFormatter1 = function(cell, formatterParams) {
 2     // to get component of cell: cell.getElement()
 3     // to get value of cell: cell.getValue()
 4     // to get row component: cell.getRow()
 5     // to get value of row: cell.getData()
 6     var rowdata = cell.getData();
 7     var timeout_ell = (Math.random() + 0.1) * 30000;
 8     setTimeout(function() {
 9         get_character(
10             rowdata["character_id"],
11             rowdata["character_canonical_name"],
12             function (data) {
13                 var result = parser.parse_character(data);
14                 cell.getElement().html("<span>" + result["japanese"] + "</span>");
15             },
16             true);
17         }, timeout_ell);
18 }

これは Tabulator の各「セル」のフォーマッタで、貼り付けた部分は「character (japanese)」列のフォーマッタ。get_character 内で AJAX してこの場合 character/110355/Phosphophyllite などから情報を取ってくる。AJAX からの非同期完了イベントに反応して「cell.getElement()」でご自由にセルをレンダリングしている、てわけである。(試しに「非同期」でなく「同期」してみるために「async: false」出来るようにしてあるが、やってみれば使い物にならんことはすぐにわかる。)

そしてさらに、わかると思うけどこれ、「20 行くらい x 4」の情報取得を要するので、何も措置しなければ Ajax making too many requests を喰らいまくる。このために適当に「リクエスト発行タイミングをバラけさせる」必要があるというわけだ。なので setTimeout を「ランダムな ellapse を渡す」ことで措置してる。ただね…、ほんとは単純なランダムはやだったんだよね。けど row.getIndex() が期待通りではなくて(バージョン問題かもなぁ)、しょうがないのでただのランダムにした。(もちろんちょっとイタチごっこる性質のもんであって、これしてもこのままでは Ajax making too many requests をゼロには出来ない。)

汎化直前、と言ったのは特に「getAsyncDataFormatter1~getAsyncDataFormatter3」のこと。これは上手に書けば formatterParams の利用で一つに出来る(可能性が高い)。でもそれをしちゃうと今時点でも結構複雑なので、「コードサンプルだぞヲラァ」に適さなくなってくるのね。

なお、「setTimeout」そのものも本当はマズい。各表の行をクリックすると表を差し替えるでしょ、ワタシの例では。ということは、古い表の方のフォーマッタが処理を終える前に表が差し替わってしまう可能性があるということ。これに立ち向かうには setInterval を「ワンショットタイマーとして使う」というアプローチでなんとでもなると思う。ワタシはやってみせないけど。