理系公務員のプログラミング日記

【ハンズオンJavaScript】非同期処理で気象庁のAPIから天気予報データを取得する

タグ:
JavaScript

とりあえず fetch と async と await を使ってみる。

API とはサーバーから html や css、JavaScript を取得するのではなく、データのみを取得する方法です。
細かい話は置いといて、気象庁の API を叩いて天気予報のデータを取得してみます。
(実際は公式の API サービスというわけではなく、リクエストしたら JSON データが取得できる状態だそうです。)

JavaScript で API からデータを取得するには、fetchメソッドを利用します。

また、これに限らず外部サーバーからデータを取得する際は、JavaScript では 非同期処理 というものが使われます。 非同期処理を実現する方法がいくつか存在しますが、最新のasync/awiat を使用して記載してみましょう。
読み方は「エィシンク/アウェイト」です。

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body></body> <script> // API配信のURL // 130000は東京のエリアコード let url_Tokyo = "https://www.jma.go.jp/bosai/forecast/data/overview_forecast/130000.json" const getWeather = async (url) => { // 指定したurlのAPIからjsonデータを取得 const response = await fetch(url) // jsonデータをオブジェクトに変換する return response.json() } const getData = async () => { data = await getWeather(url_Tokyo); console.log(data); console.log(data.publishingOffice); console.log(data.reportDatetime); console.log(data.targetArea); console.log(data.text); } getData() </script> </html>

下記のような天気予報の概要が取得できます。現在は梅雨です。

天気予報サンプル

非同期処理について

JavaScrip は シングルスレッド でのみ実行される言語です。
スレッドとは1つの処理の流れのブロックみたいなものです。
Java では マルチスレッド といって、複数のコードを並列して実行する機能がサポートされています。
マルチスレッドの機能が利用できると、メインの処理を1つのスレッドで動かす裏で、サーバーから画像や動画などのデータをダウンロードするという時間のかかる処理を別のスレッドで行うことができます。
しかし JavaScript はマルチスレッドが利用できません。そのため、同時に1つの処理しかできないため データをダウンロードする ような時間のかかる処理が始まると、別の処理がストップしてしまいます。

この問題に対処する仕組みが 非同期処理 です。

ちなみに addEventListener("click",function(){}) で定義されるイベント処理は非同期処理の一種になります。

Promise(ES2015~)

いろんな書籍ではここで コールバック関数コールバック地獄 の話が入るのですが、割愛します。

JavaScript の非同期処理は、その実行結果が Promise オブジェクト に含まれているという形で表現します。
ここで、データをダウンロードする非同期処理を考えます。データのダウンロードという処理は、問題なく成功する場合と通信エラーなどで失敗する場合があります。

Promise オブジェクトはこの成功したときの処理を resolveメソッド 、失敗したときの処理を rejectメソッド で定義し、こんな感じで Promise インスタンスを作成します。

const promise = new Promise((resolve, reject) => { resolve( // 非同期処理として実行したい内容 ); reject( // 失敗したときに実行したい内容(エラーを表示など) ); }); // 簡略化した書き方 const promiseResolve = Promise.resolve() const promiseReject = Promise.reject()

サンプルで利用したfetch()メソッドは、データのダウンロードという処理をこの Promise オブジェクトを利用して表現しています。
fetch() メソッドは戻り値として指定した url からダウンロードするという処理をresolve()の中に持った Promise オブジェクトを返してくれます。

Promise が実装されて以降、データのダウンロードなどの処理を行うライブラリはほとんどが戻り値は Promise オブジェクトの形になっています。
ですので、最初の頃は new Promise() といった処理を書く機会は少ないと思います。

async/await(ES2017~)

async/await は基本的にはセットで使います。

async は関数定義を行うときに使用するキーワードです。async をつけて定義した関数は戻り値として Promise インスタンスを返すようになります。

async function doAsync() { return "値"; } // アロー関数で書く const doAsync = async () => { return "値"; } // 同じ意味 function doAsync() { return Promise.resolve("値"); } //これも同じ function doAsync() { return new Promise((resolve, reject) => { resolve("値"); }); }

awaitasync で定義された関数内で利用できる式です。
右辺に Promise インスタンスを置きます。そのPromise インスタンスが成功または失敗するまで待機し、完了し次第式の処理を再開します。

async function doAsync() => { // 非同期処理 } async function asyncMain() => { // doAsync完了まで待つ // doAsyncが成功すれば、その結果をnumに代入 // doAsyncが失敗すれば、エラーを発生させる const num = await doAsync(); // 次の行はdoAsyncの非同期処理が完了されるまで実行されない console.log("この行は非同期処理の完了後に実行される"); }

非同期処理は少し難解な箇所ですが、サーバからデータを取得するという頻繁に行う動作で必須ですのでぜひ理解してください。

参考
気象庁の天気予報 JSON ファイルを WebAPI 的に利用したサンプルアプリ
新しい気象庁サイトから JSON データが取得できる件
JavaScript Promise の本