🌟
コールバック関数について調べてみる
chatGPTを使ってコールバック関数について調べてみました。
現在のレベル
「コールバック関数って、関数内で呼び出される関数のことでしょ?」
「なんかPromiseの登場によって使わてもよくなったやつ?」
(質問)コールバック関数について、初学者でも分かるように説明してください。
コールバック関数(callback function)とは、ある処理が終わった後に
「次に実行するために呼ばれる関数」のことです。
簡単に言うと、「関数の中に渡す、後で実行される関数」 です。
■コールバック関数を使う理由
通常、プログラムは上から下に順番に実行されますが、コールバック関数は、
例えば非同期処理(時間がかかる処理)をした後に別の処理を行いたい場合に使います。
例えば:
・サーバーからデータを取得した後に、取得したデータを使って別の処理をしたい。
・ユーザーがボタンをクリックした後に、特定のアクションを実行したい。
■コールバック関数の基本的な使い方
コールバック関数は、他の関数に引数として渡して、実行が完了したタイミングで呼ばれます。
function greet(name, callback) {
console.log("Hello, " + name);
callback(); // コールバック関数を呼び出す
}
function sayGoodbye() {
console.log("Goodbye!");
}
greet("Alice", sayGoodbye); // 「Hello, Alice」が表示された後、「Goodbye!」が表示される
つまり、関数の中で呼び出される関数というだけではなく、実行されるタイミング(非同期処理)をコントロールできることが重要という訳ですね。
(質問)Promiseとの関係について教えてください。
■コールバック関数とPromiseの違い
コールバック関数:
非同期処理が完了した後に実行される関数を指定します。
非同期処理が複雑になると、コールバック関数が入れ子(ネスト)になって、
コードが見づらくなることがあります(これを「コールバック地獄」と呼びます)。
Promise:
非同期処理を扱うためのオブジェクトで、処理が成功した場合や失敗した場合に
どのように結果を扱うかを指定します。
Promiseは、非同期処理が完了する前に値を返さない代わりに、
後で結果が返ってくることを約束(Promise)するものです。
■Promiseを使った例
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = "データ取得成功!";
resolve(data); // データ取得成功した場合
}, 1000);
});
}
fetchData()
.then(result => {
console.log(result); // データ取得成功!
return "次の処理";
})
.then(nextResult => {
console.log(nextResult); // 次の処理
})
.catch(error => {
console.error("エラー:", error); // エラー処理
});
■Promiseを使うメリット
- 非同期処理のチェーン: .then() を使って、非同期処理の結果を順番に処理することができます。
- エラーハンドリング: .catch() でエラーを一元的に処理できます。
- 可読性の向上: 非同期処理の順番が明確になり、コードが読みやすくなります。
(質問)Promiseでなく、コールバック関数を使わざるを得ない場合はありますか?
解答はいくつかあったのですが、下記が重要と感じました。
■イベントリスナー(リアルタイム処理)の場合
Promiseは一度しか解決(resolve/reject)できないため、
繰り返し発生するイベントには向いていません。
イベントリスナーを使う場合は、コールバック関数が必要になります。
document.addEventListener("click", () => {
console.log("クリックされました!");
});
なぜPromiseを使えない?
Promise は 一度しか実行されない ため、複数回のクリックを処理できません。
イベントが発生するたびに実行される処理は、コールバック関数が最適です。
■JavaScriptの一部の非同期処理(例えば、setTimeout)
setTimeout や setInterval などの組み込み関数は、コールバック関数しか受け付けません。
setTimeout(() => {
console.log("3秒後に実行されました!");
}, 3000);
まとめ
今回はコールバック関数について調べました。
とりあえずPromiseを使っていればいいやと思っていましたが、コールバック関数が必要になるケースについても知ることができました。
次はasync/awaitとの関係についても学習したいと思いますが、長くなりそうなので一旦区切りたいと思います。
Discussion
そこで asyncIterator すればいいのでは……?
Promise なら await だが、 asyncIterator なら for await ... of が使えますし。
ちなみに Promise.withResolvers() を使えば resolve用のコールバックと待てる promise が取得できます。
例えば asyncIterator を似たように使いたいなら次の様に書けます。
ReadableStream の values() は safari はまだなので、 gemini さんに for await が出来る状態で書き換えてもらうと次の感じになります。
コメントありがとうございます
まだasyncIteratorやPromise.withResolvers()が必要になるような複雑な処理は扱ったことがなく、
勉強になります。
自身のメモとして、下記を載せておきます。