あらすじ
Qiitaのリニューアル前に記事ページの右カラムに表示されていた 人気の投稿 をローカル環境で復活させようと思い、APIにリクエストをして投稿データを取得し、いいねの多い上位5件のタイトルとURLを取り出して、右カラムにHTMLで追加する、という処理を UserScript で書いたのですが、APIのリクエスト回数制限に引っかかって 泣く泣くお蔵入りしました。(実装する前に気づけよ)
* 本当はこんなの作ろうとしてました
リニューアル以前の Qiita でこんなのあったかとおもいます。一応期待どおり動きはしたんですが、リクエスト回数がすぐ上限に達してしまうので使い物にならないのが現状です。悔しい。
じゃあ今日は何の話か
前項に書いた 全件取得するまで $.ajax
を呼び続ける というパターンはわりと今後も出番ありそうかとおもいましたため、今日は作ったコードをサンプルとして公開してみたいと思います。
検証ブラウザ
- Google Chrome(70.0.3538.77)
IEだとたぶん動かないです。
サンプルコード
というわけでこれが全件取得するまで $.ajax
を呼び続けるコード例です。(jQuery は事前に読み込まれているものとします。)
私の場合は Qiita の API の仕様が最大でも100件づつしか取得できない というものであったため、記事が100件以上あるユーザーの場合は何度も $.ajax を呼ぶ必要があったことからこのようなコードが必要になりました。
※更新:わかりやすくするため処理の骨子を残して余計なものはごっそりカットしました。当初作ったコードを見てみたい方はお手数ですがこの記事の編集履歴から過去のコードをご覧ください。
(function($){
//1回のAPIリクエストで取得する件数
const perPage = 100;
//fetchPosts が実行されるたびここに記事が貯まります
let posts = [];
//APIからデータを取得します
const fetchPosts = (userId, page) => {
return $.ajax({
type: "get",
url: "//example.com/path/to/api",
data: {
user_id: userId
page: page,
per_page: perPage
}
}).then(items => {
//取得結果を貯める
posts = posts.concat(items);
//次ページがありそうなときは再帰呼び出し
if(items.length == perPage) {
fetchPosts(userId, page++);
}
return posts;
});
};
//Main
$(function(){
const page = 1;
//fetchPosts は Promise を返すので then で続けて処理が書けます
fetchPosts(userId, page).then((posts) => {
//APIで取得したデータを使っていろいろやる
});
});
})(jQuery);
この処理の要点
下記の部分です。再帰呼び出し をすることでわりとあっさり実現できました。また、この if 文の条件で繰り返し処理の継続如何をコントロールできます。fetchPosts は Promise ごと返して、ソートなどの後処理は大元の呼び出し側に任せています。
if(items.length == perPage) {
fetchPosts(userId, page++);
}
感想
当初、while文内で $.ajax するようなコードを書いてうんうん唸っていたのはいい思ひ出(遠い目
ちなみにこの人気の投稿欄復活は諦めていないので、何か別の作戦を考えてまたリベンジしたいと思います。
※2018/11/21追記
リベンジしてみました。
[Qiita]なつかしの "人気の投稿" 欄を UserScript で復活させる(β版) - Qiita