👋
関西人のボクがJS/TSのPromiseについて解説するで
TypeScript Promise について
まいど!TypeScriptの勉強は捗ってまっか?とりあえず何か作って勉強や!と意気込んだものの、いきなりプロミスがよーわからんってなったそこの君!今日もとりあえず分かった風になれる簡単解説をお届けするで!
Promiseってなんやねん?
Promiseっちゅうんは、非同期処理を扱うためのオブジェクトやで。要するに「今すぐには結果が分からんけど、後で結果を教えたるわ」っちゅう約束みたいなもんや。プロミスって約束のことやしな。
JavaScriptでもTypeScriptでも使えるけど、TypeScriptやとちゃんと型がついて安心やね。
基本的な使い方
Promiseの作り方
// 基本的なPromiseの作り方やで
const myPromise = new Promise<string>((resolve, reject) => {
// 何か処理をして...
if (処理が成功したら) {
resolve("うまいこといったで!");
} else {
reject("あかん、失敗したわ");
}
});
then/catchで結果を受け取る
myPromise
.then((result) => {
console.log(result); // "うまいこといったで!"
})
.catch((error) => {
console.error(error); // "あかん、失敗したわ"
});
async/await で書く方がスッキリやで
async function doSomething() {
try {
const result = await myPromise;
console.log(result);
} catch (error) {
console.error(error);
}
}
よう使うシーン
1. API呼び出し
async function fetchUserData(userId: number): Promise<User> {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error("API呼び出しでコケたわ");
}
return response.json();
}
2. ファイル読み込み
function readFile(filename: string): Promise<string> {
return new Promise((resolve, reject) => {
// ファイル読み込み処理
fs.readFile(filename, 'utf8', (err, data) => {
if (err) {
reject("ファイル読めんかったわ");
} else {
resolve(data);
}
});
});
}
3. タイマー処理
function delay(ms: number): Promise<void> {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, ms);
});
}
// 使う時
await delay(1000); // 1秒待つで
console.log("1秒経ったで!");
4. 複数のPromiseを組み合わせる
// 全部完了するまで待つ
const results = await Promise.all([
fetchUserData(1),
fetchUserData(2),
fetchUserData(3)
]);
// どれか一つでも完了したらOK
const fastestResult = await Promise.race([
fetchFromAPI1(),
fetchFromAPI2()
]);
TypeScriptでの型指定
基本的な型指定
// 戻り値の型を明示的に指定
const numberPromise: Promise<number> = new Promise((resolve) => {
resolve(42);
});
// 関数の戻り値として
async function getString(): Promise<string> {
return "関西弁やで";
}
ジェネリクスを使った柔軟な型指定
function wrapInPromise<T>(value: T): Promise<T> {
return Promise.resolve(value);
}
const stringPromise = wrapInPromise("たこ焼き"); // Promise<string>
const numberPromise = wrapInPromise(123); // Promise<number>
よくある質問とその答え
Q: PromiseとCallbackの違いって何やねん?
A: Callbackはコールバック地獄っちゅう問題があるねん。Promiseやとチェーンできるし、async/awaitで同期的に書けるから読みやすいで。
// Callback地獄(あかん例)
getData((data) => {
processData(data, (processed) => {
saveData(processed, (saved) => {
console.log("やっと終わったわ...");
});
});
});
// Promise(ええ例)
getData()
.then(processData)
.then(saveData)
.then(() => console.log("スッキリやな!"));
Q: async/awaitとthen/catchどっち使ったらええの?
A: 基本的にはasync/awaitがおすすめやで。読みやすいし、エラーハンドリングもtry/catchで統一できるからな。
Q: Promiseのエラーハンドリングで気をつけることは?
A: 必ずcatchするかtry/catchで囲むことや!エラーを放置したらUnhandled Promise Rejectionになって怒られるで。
// あかん例
fetchData(); // エラーが起きても無視される
// ええ例
fetchData().catch(console.error);
// もっとええ例
try {
await fetchData();
} catch (error) {
console.error("エラー起きたで:", error);
}
Q: Promise.allとPromise.allSettledの違いって?
A:
-
Promise.all
: 一つでも失敗したら全部失敗扱い -
Promise.allSettled
: 成功でも失敗でも全部の結果を待つ
// Promise.all - 一つでもコケたら全部アウト
try {
const results = await Promise.all([promise1, promise2, promise3]);
} catch (error) {
console.log("どれかがコケたわ");
}
// Promise.allSettled - 全部の結果を見る
const results = await Promise.allSettled([promise1, promise2, promise3]);
results.forEach((result) => {
if (result.status === 'fulfilled') {
console.log("成功:", result.value);
} else {
console.log("失敗:", result.reason);
}
});
Q: Promiseチェーンで値を渡すにはどうしたらええの?
A: thenの戻り値が次のthenに渡されるで。async/awaitやと普通に変数で受け取れるから楽やね。
// Promiseチェーン
fetchUserData(1)
.then(user => user.name)
.then(name => `こんにちは、${name}さん`)
.then(greeting => console.log(greeting));
// async/await
const user = await fetchUserData(1);
const greeting = `こんにちは、${user.name}さん`;
console.log(greeting);
まとめ
Promiseは非同期処理の必須アイテムやで!最初はとっつきにくいかもしれんけど、慣れたら便利すぎて手放せんくなるわ。特にTypeScriptやと型安全で安心やしな。
ポイントは:
- async/awaitを積極的に使う
- エラーハンドリングを忘れん
- 型指定をちゃんとする
- Promise.allやPromise.raceもうまく活用する
ちなみにワイはプロミスよりアコム派やで!キミもほどほどにな!
Discussion