JavaScriptのコールバック関数とは?

JavaScript

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");
        });
    });
});

このような深いネストを避けるために、Promiseasync/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();

このように Promiseasync/await を使うことで、可読性の高いコードを書けるようになります。

まとめ

  • コールバック関数は、関数の引数として渡され、後で実行される関数。
  • 非同期処理やイベント処理、配列操作などに広く使われる。
  • コールバックのネストが深くなると「コールバック地獄」が発生する。
  • Promiseasync/await を使うことで、コールバックの課題を解決できる。

コールバック関数の仕組みを理解して、より効率的なJavaScriptのコーディングを目指しましょう!

コメント

タイトルとURLをコピーしました