複数のIT勉強会イベントのAPIを使ってカレンダー表示しているサイトはいくつもあるけれど、
リスト表示したり、自分が思った通りのレイアウトで出したかったのでJavascriptを使ってAPIからイベント情報を取得した話。
connpassと、atndと、doorkeeperのAPIを非同期で処理しつつ最後に取得した結果をまとめたい。
それぞれのサービスでは1回で全件取得できないので、複数回に分けてAPIを呼ぶ必要があるが、同じサービス内で非同期で処理すると負荷をかけてしまうのが心配なので、同じAPIに対しては同期的に処理したい。
非同期、同期処理はES2017の「async / await」が便利なので使う。IEでは使えない。
APIを読み込んで同期的に結果を変数に格納する場合。
(async () => {
let events = [];
let event = [];
let data = [];
// connpassのデータ取得
data = await $.ajax({url: 'connpassのURL', dataType: 'jsonp'});
event = connpass(data); // 取得したjsonの結果を共通の形式の配列に変換
events = events.concat(event); // イベント情報の配列に追記
// atndのデータ取得
data = await $.ajax({url: 'atndのURL', dataType: 'jsonp'});
event = atnd(data); // 取得したjsonの結果を共通の形式の配列に変換
events = events.concat(event); // イベント情報の配列に追記
callback(events); // イベント情報の表示を行う処理
})();
awaitを入れると同期通信になって戻り値が取れるので便利。
一度に全件取得できないので(APIによって100件単位など)、複数回APIを呼び出す。
(async () => {
let events = [];
let event = [];
let data = [];
// connpassのデータ取得(100件を10回)
for (let i = 0; i < 10; i++) {
data = await $.ajax({url: 'connpassのURL?start=' + (i * 100 + 1), dataType: 'jsonp'});
event = connpass(data); // 取得したjsonの結果を共通の形式の配列に変換
events = events.concat(event); // イベント情報の配列に追記
}
// atndのデータ取得(100件を10回)
for (let i = 0; i < 10; i++) {
data = await $.ajax({url: 'atndのURL?start=' + (i * 100 + 1), dataType: 'jsonp'});
event = atnd(data); // 取得したjsonの結果を共通の形式の配列に変換
events = events.concat(event); // イベント情報の配列に追記
}
callback(events); // イベント情報の表示を行う処理
})();
上記の方法だと、全て20件とも同期的に順番に動いてしまうので、時間がかかってしまう。
connpassと、atndのAPIに対して非同期に動作すれば、10件分の時間に短縮出来る。
全部非同期にすれば1件分の時間で済むはずだが、同じAPIに対して10件分同時アクセスになってしまい、負荷をかけてしまうかも知れないので、同一APIでは同期的にアクセスする。
(async () => {
let events = [];
let event = [];
let data = [];
let results = [];
// connpassのデータ取得(100件を10回)
results.push((async () => {
for (let i = 0; i < 10; i++) {
data = await $.ajax({url: 'connpassのURL?start=' + (i * 100 + 1), dataType: 'jsonp'});
event = connpass(data); // 取得したjsonの結果を共通の形式の配列に変換
events = events.concat(event); // イベント情報の配列に追記
}
})());
// atndのデータ取得(100件を10回)
results.push((async () => {
for (let i = 0; i < 10; i++) {
data = await $.ajax({url: 'atndのURL?start=' + (i * 100 + 1), dataType: 'jsonp'});
event = atnd(data); // 取得したjsonの結果を共通の形式の配列に変換
events = events.concat(event); // イベント情報の配列に追記
}
})());
await Promise.all(results); // 非同期処理の結果をまとめて受け取る。
callback(events); // イベント情報の表示を行う処理
})();
非同期処理の結果を最後にまとめて取得するのにはPromise.allを使用する。
全体のasyncに加えて、API毎にもasyncを指定することで、異なるAPIは非同期で、同一APIでは同期処理になる。
Promise.allで其々の処理を並列で実行して結果を取得する。
参考URL
最終的な成果物は以下の通り
使用したイベントAPIは以下の通り
APIから取得したイベント情報を配列に整形して、FullCalendar.jsのライブラリにセットして、カレンダー表示やリスト表示をおこなっている。
FullCalendar.jsはVersion3まではJQueryを使用していたが、最新のVersion4からJQueryを使用しなくなっている。JQueryを使用してるVersion3までの記事が多いので注意。