JavaScriptで非同期処理をするときに一番使われる技術に「Promise」「async」「await」があります。本記事は、その基本として「なぜ必要なのか」を分かりやすく解説します。また、これらを使う際の“決まりごと”や“使い方の型”も紹介します。
非同期処理とは
JavaScriptは基本的に1本のスレッド(単線)で動作します。
たとえばネットワーク経由のAPI呼び出しなど、答えが返ってくるまで時間がかかる処理を直接動かすと、他の処理が止まってしまいます。
そこで、JavaScriptは "非同期" にする方法として Promise
という構造を用意しています。
Promiseとは
Promiseは、一言で言うと「後で答えが返ってくるボックス」です。
Promiseの基本形
function doSomethingAsync() {
return new Promise((resolve, reject) => {
// 非同期な処理
setTimeout(() => {
resolve("成功");
}, 1000);
});
}
使い方: .then()
doSomethingAsync().then(result => {
console.log(result); // => "成功"
}).catch(error => {
console.error(error);
});
async/awaitはPromiseの簡単表現
.then()
を使うと処理がネストして書きづらくなることがあります。
async
/await
を使うと、一要する「Promiseをまるで普通の値のように書ける」ようになります。
例:
async function run() {
try {
const result = await doSomethingAsync();
console.log(result); // => "成功"
} catch (error) {
console.error(error);
}
}
awaitの特徴と「決まりごと」
✅ await
は Promise を「待つ」ためのもの
const result = await somePromise();
✅ await
は async function
の中でしか使えない
// ❌ エラーになる例
const result = await somePromise(); // async function の外では使えない
// ✅ 正しい例
async function getResult() {
const result = await somePromise();
return result;
}
✅ await
の対象が普通の値でもOK(即座に返る)
const x = await 42; // OK, x === 42
const y = await "Hello"; // OK, y === "Hello"
✅ Promiseが返る関数を「呼び出す側」は await
か .then()
で結果を処理
// 関数定義
function fetchData() {
return new Promise(resolve => setTimeout(() => resolve("done"), 1000));
}
// 呼び出し
const result = await fetchData(); // ✅ await方式
fetchData().then(result => {...}); // ✅ .then()方式
❌ よくある間違い
const result = fetchData();
console.log(result); // Promiseオブジェクトが出てきて中身が取れない
callback型APIをPromise化する理由
コールバック型APIは結果を return
ではなく callback(result)
として返します。
悪い例:
function getValue() {
let result;
chrome.storage.sync.get(["token"], (data) => {
result = data.token;
});
return result; // => undefined!
}
よい例 (Promise化)
function getValue() {
return new Promise((resolve) => {
chrome.storage.sync.get(["token"], (data) => {
resolve(data.token);
});
});
}
const token = await getValue();
補足:.then()とawaitの違いと使いどころ
Promiseの結果は .then() または await で受け取ることができますが、使い方には違いがあります。
.then()
の中でしか値を扱えない理由
.then()
は非同期処理が完了したときに実行されるコールバックです。そのため、その中でしか値を安全に使えません。
let result;
getValue().then(res => {
result = res;
});
console.log(result); // ❌ まだundefinedのまま
await
を使うと「一時停止してから処理を続ける」
await
は Promise が解決するのを待ち、その結果をまるで変数のように受け取れます。
const result = await getValue();
console.log(result); // ✅ 正しく値が取れる
await
は .then()
の Syntax Sugar
await
は内部的には .then()
を使って処理しています。ただし await
を使うことで、コードを同期的に書けて可読性が上がります。
async function
の内部全体は Promise の中に包まれています。そのため await
で「いったん止まる」→「続きが .then()
の中身と同様に動く」という流れになります。
asyncをつける必要があるか
asyncが必要なのは:
- 関数内で
await
を使う場合 - 普通の値を
Promise
として自動的に返したい場合(syntactic sugar)
asyncが不要なのは:
- すでに
return new Promise(...)
している場合 - 内部で
await
を使わない場合
総まとめ:使い方の“型”
✅ Promiseを返す関数の作り方
function getData() {
return new Promise((resolve, reject) => {
resolve("OK");
});
}
✅ async/awaitで呼び出す
async function main() {
const result = await getData();
console.log(result);
}
✅ async/awaitとthenの併用も可能(ただし可読性に注意)
async function main() {
getData().then(result => console.log(result));
// or
const result = await getData();
}
総結
技術 | 使用目的 |
---|---|
Promise |
非同期な処理をラップする |
.then() |
Promiseの結果を受け取る |
async |
関数を Promiseを返すようにする/内部でawaitを使うために必要 |
await |
Promiseの結果を待って使う |
Promiseやasync/awaitを理解すると、JavaScriptの非同期処理がとても読みやすく、書きやすくなります。