28.
非同期処理2
Promiseの基本
Promise
Promise(プロミス)は、非同期処理するオブジェクトです。非同期な操作が成功した場合にはresolved(解決)し、失敗したときはrejected(拒否)し、thenキーワードで処理を分岐します。
const promise = new Promise((resolve, reject) => {
// 成功時は resolve(value) を呼び出す
// 失敗時は reject(error) を呼び出す
});
promise.then((value) => {
// resolve() で呼び出された処理
}).catch((error) => {
// reject() で呼び出された処理
});
- ペンディング(Pending): Promiseが作成された初期状態
- 解決(Resolve): Promiseが成功した状態
- 拒否(Rejected): Promiseが失敗した状態
async/await
async/awaitは、JavaScriptで非同期処理をより簡潔かつ直感的に扱うための構文です。
async
asyncキーワードは、非同期関数(asynchronous function)を定義するために利用します。
//非同期関数
async function getData() {
}
await
awaitキーワードは、async関数の処理完了を待機するために利用します。
functionの場合
async function getData() {
//ネットワーク接続して、処理完了を待機を待機
const response = await fetch('https://api.example.com/data');
}
無名関数の場合
const getData = async function() {
//ネットワーク接続して、処理完了を待機を待機
const response = await fetch('https://api.example.com/data');
}
アロー関数の場合
const getData = async () => {
//ネットワーク接続して、処理完了を待機を待機
const response = await fetch('https://api.example.com/data');
}
Promiseで非同期処理
Promiseで非同期処理をします。
ファイル構成
promise/
├── js
│ └── app.js
└── app.html
app.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ランダム名言アプリ</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center py-10">
<div class="w-full max-w-xl bg-white p-6 rounded-lg shadow">
<h1 class="text-2xl font-bold text-center mb-6">ランダム名言アプリ</h1>
<div class="text-center mb-4">
<button id="fetch-quote-button" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
名言を取得
</button>
</div>
<div id="loading" class="text-center text-gray-500 hidden">名言を取得中...</div>
<div id="error" class="text-center text-red-500 hidden"></div>
<div id="quote" class="mt-4 text-center text-lg font-semibold hidden"></div>
<div id="author" class="text-center text-gray-500 hidden"></div>
</div>
<script src="js/app.js"></script>
</body>
</html>
Promise生成
Promiseオブジェクト
fetchRandomQuote() を定義し、Promiseオブジェクトを生成して返します。
js/app.js
function fetchRandomQuote() {
return new Promise((resolve, reject) => {
});
}
ローディング処理と待ち時間
ローディングを表示して、setTimeout() で強制的に待ち時間を作成します。
js/app.js
function fetchRandomQuote() {
return new Promise((resolve, reject) => {
loadingDiv.classList.remove("hidden");
errorDiv.classList.add("hidden");
quoteDiv.classList.add("hidden");
authorDiv.classList.add("hidden");
setTimeout(() => {
}, 2000);
});
}
データレスポンス処理
確率を使って成功時に resolve()、失敗時に reject() を実行します。
js/app.js
function fetchRandomQuote() {
return new Promise((resolve, reject) => {
loadingDiv.classList.remove("hidden");
errorDiv.classList.add("hidden");
quoteDiv.classList.add("hidden");
authorDiv.classList.add("hidden");
setTimeout(() => {
// 80%の確率で成功
const success = Math.random() > 0.2;
if (success) {
const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
resolve(randomQuote);
} else {
reject("名言の取得に失敗しました。");
}
}, 2000);
});
}
ボタンクリックイベント
ボタンクリックで handlerRandomQuote() を実行します。
js/app.js
// ボタンクリックイベント
fetchQuoteButton.addEventListener("click", handlerRandomQuote);
Promise実行
then() で処理
handlerRandomQuote() で fetchRandomQuote() を実行します。 実行結果は、then() で resolve(), reject() を分岐処理します。
js/app.js
function handlerRandomQuote() {
fetchRandomQuote()
.then(quote => {
displayQuote(quote);
})
.catch(error => {
displayError(error);
})
.finally(() => {
loadingDiv.classList.add("hidden");
});
}
// ボタンクリックイベント
fetchQuoteButton.addEventListener("click", handlerRandomQuote);
async/await で処理
async/await でコーディングした場合です。
js/app.js
fetchQuoteButton.addEventListener("click", async () => {
try {
const quote = await fetchRandomQuote();
displayQuote(quote);
} catch (error) {
displayError(error);
} finally {
loadingDiv.classList.add("hidden");
}
});
指定した時間後に、結果が表示されるか確認します。
ブラウザ

fetch API
fetch APIとは
fetch APIは、JavaScriptでネットワーク通信するためのAPIで、ブラウザアプリでサーバーとのデータの送受信ができます。XMLHttpRequestよりも現代的な非同期処理ができます。
fetch()
fetch() はネットワークリクエストするための非同期メソッドで、then() または async/await で非同期処理します。
then() の場合
fetch(URL).then()
async/awaitの場合
async function getData() {
const response = await fetch(URL)
}
Responseオブジェクト
非同期処理の結果は、Responseオブジェクトで取得できます。
json()
json() はResponseオブジェクトのメソッドで、取得したJSONデータをJavaScriptのオブジェクトに変換します。
response.json();
text()
text() はResponseオブジェクトのメソッドで、取得したデータをテキストで取得します。
response.text();
JSONオブジェクト
取得したJSONデータをJavaScriptのオブジェクト変換
JSON.parse(text)
非同期処理
then() または async/await で非同期処理します。
then()
fetch() は、then() ブロック内で非同期処理をメソッドチェインし、リクエストの成功・失敗の処理を記述できます。
// 非同期でリクエスト
fetch('https://api.example.com/data')
.then(response => {
// レスポンスを取得し、JSONデータを変換して返す
return response.json();
})
.then(data => {
// 変換されたデータを処理
console.log(data);
})
.catch(error => {
// 予期せぬエラー
console.error('Error:', error);
});
async/await
async のスコープ内で、await で非同期処理します。
async function getData() {
try {
// 非同期でリクエストし、レスポンスを取得
const response = await fetch('https://api.example.com/data');
// JSONデータを変換
const data = await response.json();
// 変換されたデータを処理
console.log(data);
} catch (error) {
// 予期せぬエラー
console.error('Error:', error);
}
}
非同期処理(async/await)
ファイル構成
├── data/
│ └── prefectures.json
├── js/
│ └── search_address.json
└── search_address.html
都道府県データ(JSON)
都道府県データのJSONファイル、data/prefectures.json を用意します。
data/prefectures.json
[
{ "code": 1, "name": "北海道" },
{ "code": 2, "name": "青森県" },
{ "code": 3, "name": "岩手県" },
{ "code": 4, "name": "宮城県" },
{ "code": 5, "name": "秋田県" },
{ "code": 6, "name": "山形県" },
{ "code": 7, "name": "福島県" },
{ "code": 8, "name": "茨城県" },
{ "code": 9, "name": "栃木県" },
{ "code": 10, "name": "群馬県" },
{ "code": 11, "name": "埼玉県" },
{ "code": 12, "name": "千葉県" },
{ "code": 13, "name": "東京都" },
{ "code": 14, "name": "神奈川県" },
{ "code": 15, "name": "新潟県" },
{ "code": 16, "name": "富山県" },
{ "code": 17, "name": "石川県" },
{ "code": 18, "name": "福井県" },
{ "code": 19, "name": "山梨県" },
{ "code": 20, "name": "長野県" },
{ "code": 21, "name": "岐阜県" },
{ "code": 22, "name": "静岡県" },
{ "code": 23, "name": "愛知県" },
{ "code": 24, "name": "三重県" },
{ "code": 25, "name": "滋賀県" },
{ "code": 26, "name": "京都府" },
{ "code": 27, "name": "大阪府" },
{ "code": 28, "name": "兵庫県" },
{ "code": 29, "name": "奈良県" },
{ "code": 30, "name": "和歌山県" },
{ "code": 31, "name": "鳥取県" },
{ "code": 32, "name": "島根県" },
{ "code": 33, "name": "岡山県" },
{ "code": 34, "name": "広島県" },
{ "code": 35, "name": "山口県" },
{ "code": 36, "name": "徳島県" },
{ "code": 37, "name": "香川県" },
{ "code": 38, "name": "愛媛県" },
{ "code": 39, "name": "高知県" },
{ "code": 40, "name": "福岡県" },
{ "code": 41, "name": "佐賀県" },
{ "code": 42, "name": "長崎県" },
{ "code": 43, "name": "熊本県" },
{ "code": 44, "name": "大分県" },
{ "code": 45, "name": "宮崎県" },
{ "code": 46, "name": "鹿児島県" },
{ "code": 47, "name": "沖縄県" }
]
HTML作成
都道府県のプルダウンのHTML作成します。
search_address.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Search address</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
<main class="container">
<h2 class="mt-3">住所検索</h2>
<div class="mb-3">
<label class="form-label" for="">都道府県</label>
<select id="prefecture" class="form-control w-25" name="prefecture">
<option value="">--- 都道府県 ---</option>
</select>
</div>
</main>
<script src="js/search_address.js"></script>
</body>
</html>
API URL生成
都道府県のJSONデータ取得APIのURLを生成します。
search_address.js
function getApiURL() {
const currentURL = location.href
const fileName = currentURL.substring(currentURL.lastIndexOf('/') + 1);
const baseURL = currentURL.replace(fileName, '');
return baseURL + 'data/prefectures.json';
}
const API_URL = getApiURL();
非同期関数作成
fetch() でAPIにアクセスし、await でデータ取得します。
search_address.js
const loadPrefectures = async () => {
const response = await fetch(API_URL);
}
レスポンス処理
JSONデータをオブジェクトに変換します。 このときawaitで待機が必要です。
search_address.js
const loadPrefectures = async () => {
const response = await fetch(API_URL);
const prefectures = await response.json();
console.log(prefectures);
}
メインプログラム
ブラウザ読み込み後に、loadPrefectures() を実行します。
search_address.js
(() => {
loadPrefectures();
})();
コンソールで都道府県データを確認してみましょう。
結果
Array(47)
プルダウン作成
createPrefectures() で、都道府県プルダウン作成処理をします。
search_address.js
const createPrefectures = (prefectures) => {
prefectures.forEach((prefecture) => {
var option = document.createElement('option')
option.value = prefecture.code;
option.innerHTML = prefecture.name;
document.getElementById('prefecture').appendChild(option)
})
}
createPrefectures() を実行します。
search_address.js
const loadPrefectures = async () => {
const response = await fetch(API_URL);
const prefectures = await response.json();
createPrefectures(prefectures);
}
非同期処理(then)
fetchAPIを then() で処理するケースです。
レスポンス
then() でレスポンスを取得し、json() でPromiseオブジェクトを返します。
search_address.js
const loadPrefecturesForThen = () => {
fetch(API_URL)
.then((response) => {
if (!response.ok) {
throw new Error('Network error');
}
console.log(response.json());
return response.json();
})
}
データ確認
PromiseオブジェクトのPromiseResultに、データが格納されています。
結果

プルダウン作成
then() を追加し、取得しデータからプルダウンを作成します。また、catch() で予期しないエラーの対処もしておきます。
search_address.js
const loadPrefecturesForThen = () => {
fetch(API_URL)
.then((response) => {
if (!response.ok) {
throw new Error('Network error');
}
return response.json();
})
.then((prefectures) => {
createPrefectures(prefectures);
})
.catch(error => {
console.log(error);
});
}
メインプログラム
HTML読み込み後に、loadPrefecturesForThen() を実行します。
search_address.js
(() => {
//loadPrefectures();
loadPrefecturesForThen();
})();