JavaScriptの「コールバック関数」とは、ある関数の引数として渡される関数のことを指します。コールバック関数は、非同期処理やイベント処理、配列操作など様々な場面で活用されます。
何言っているかわけわからないと思うので実際のコードを見ながら解説していきます。
コールバック関数の基本
コールバック関数は、他の関数に渡されて、その関数の中で実行されます。簡単な例を見てみましょう。
function greeting(name, callback) {
console.log("Hello, " + name + "!");
callback();
}
function afterGreeting() {
console.log("Nice to meet you!");
}
greeting("Alice", afterGreeting);
実行結果
Hello, Alice!
Nice to meet you!
この例では、「greeting」
関数に 「afterGreeting
」 をコールバック関数として渡し、「greeting
」 内で 「callback()
」 を呼び出すことで、順番に処理が実行されるようになっています。
非同期処理でのコールバック
JavaScriptでは、非同期処理を扱うときにコールバック関数がよく使われます。例えば、「setTimeout
」 を使った例を見てみましょう。
function delayedMessage(message, delay, callback) {
setTimeout(() => {
console.log(message);
callback();
}, delay);
}
delayedMessage("This message is delayed", 2000, () => {
console.log("This is executed after the delay.");
});
実行結果(2秒後に表示)
This message is delayed
This is executed after the delay.
このように、非同期処理が完了した後に実行したい処理をコールバック関数として渡すことで、順序をコントロールできます。
配列操作におけるコールバック
JavaScriptの配列メソッドの多くは、コールバック関数を引数に取る仕様になっています。例えば、「forEach
」 や 「map
」 などです。
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((num) => {
console.log(num * 2);
});
実行結果
2
4
6
8
10
この例では、配列 numbers
の各要素に対して forEach
のコールバック関数が適用され、各要素が2倍されて出力されます。
コールバックの問題点と解決策
コールバック関数を使うことで、非同期処理やイベント処理を簡単に扱うことができます。しかし、ネストが深くなり「コールバック地獄(callback hell)」と呼ばれる可読性の低いコードになってしまうことがあります。
コールバック地獄の例
以下のコードは読み飛ばしてください。めっちゃ読みにくいです。
function step1(callback) {
setTimeout(() => {
console.log("Step 1 complete");
callback();
}, 1000);
}
function step2(callback) {
setTimeout(() => {
console.log("Step 2 complete");
callback();
}, 1000);
}
function step3(callback) {
setTimeout(() => {
console.log("Step 3 complete");
callback();
}, 1000);
}
step1(() => {
step2(() => {
step3(() => {
console.log("All steps complete");
});
});
});
このような深いネストを避けるために、Promise
や async/await
を使うことが推奨されます。
Promiseを使ったリファクタリング
function step1() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Step 1 complete");
resolve();
}, 1000);
});
}
function step2() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Step 2 complete");
resolve();
}, 1000);
});
}
function step3() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Step 3 complete");
resolve();
}, 1000);
});
}
step1()
.then(() => step2())
.then(() => step3())
.then(() => console.log("All steps complete"));
async/await を使ったリファクタリング
async function runSteps() {
await step1();
await step2();
await step3();
console.log("All steps complete");
}
runSteps();
このように Promise
や async/await
を使うことで、可読性の高いコードを書けるようになります。
まとめ
- コールバック関数は、関数の引数として渡され、後で実行される関数。
- 非同期処理やイベント処理、配列操作などに広く使われる。
- コールバックのネストが深くなると「コールバック地獄」が発生する。
Promise
やasync/await
を使うことで、コールバックの課題を解決できる。
コールバック関数の仕組みを理解して、より効率的なJavaScriptのコーディングを目指しましょう!
コメント