👋

関西人のボクが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