_コールバック_関数とは、他の関数に引数として渡される関数のことです。コールバック関数は、その後の処理を引き起こすために呼び出されることがあります。_コールバック_は、行った処理の結果を扱ったり、イベントが発生したときの動作を扱ったりするためによく使われます。_コールバック_関数は、同期プログラミングでも非同期プログラミングでも使うことができます。
const sideLength = 5;
// Caller function takes a callback function
function applySideLength(callback) {
return callback(sideLength);
}
// Callback must expect the possible argument from the calling function
function areaOfSquare(side) {
return side * side;
}
applySideLength(areaOfSquare); // => 25
コールバックは、関数式として書くこともできます。
applySideLength(function squarePerimeter(side) {
return side * 4;
});
これはJavaScriptで便利なパターンです。JavaScriptは、一度に1つの関数呼び出ししか実行できないシングルスレッドのランタイムとして設計されているからです。実行中は、その関数が戻るまで、ランタイムは他のイベントに応答することも、実行を続けることもできません。
多くのAPI呼び出し(I/O関数、タイマー、イベントリスナーなど)は、処理が完了するまで現在の関数呼び出しを脇に置いておくために、非同期の仕組みを使います。処理が完了すると、コールバック関数がメッセージキューに置かれます。こうして、ランタイムが関数呼び出しと関数呼び出しの合間にあるときに、コールバック関数を呼び出すことでメッセージが処理されます。
また、_コールバック関数_を使うことには、あとで呼び出される側の関数からは参照できないクロージャスコープ内の変数を参照できるという利点もあります。
_イベントハンドラー_は、JavaScriptにおけるコールバックの一般的な用途です。'onload'や'onclick'のようなブラウザーイベントは、関数が呼び出されるきっかけになるシグナルです。DOMの[Document Object ModelオブジェクトのaddEventListenerメソッドは、イベントが発生したことを「聞き取る」と、呼び出されるコールバック関数を登録します。
document.addEventListener('onload', function () {
alert('The webpage has now been loaded');
});
Node.jsでは、コールバック関数は、プログラムの流れを制御するために規約に従います。パターンは次のとおりです。コールバック関数の最初の引数はErrorまたはnullを受け取ることがあります。2番目以降の引数は、呼び出し側の関数が送るように設計されたデータを受け取ります。
エラーが発生した場合、2番目以降の引数は存在しないことがあるため、それらが存在することを前提にしてはいけません。
function operation(a, b, callback) {
// Work ...
if (/* an error occurs */) {
return callback(new Error('An error occurred'))
}
// On success:
callback(null, data)
}
function callback(error, returnedData) {
if (error) {
// An error occurred, handle it here.
return
}
// No error occurred, continue with the returned data.
}
operation(1, 2, callback)
非同期関数を扱うとき、流れを制御する助けとして、このパターンをよく目にします。
よく使うArrayの関数は、その動作を定義するためにコールバック関数を使います。
Array.prototype.forEach:
コールバックを受け取り、配列の各要素にそのコールバックを適用します。
[1, 2, 3].forEach(function (element) {
doSomething(element);
});
// => doSomething() is invoked 3 times, once with each element
Array.prototype.map
コールバックを受け取り、配列の各要素にそのコールバックを適用し、その結果を使って新しい配列を作ります。
[1, 2, 3].map(function (element) {
return element + 1;
});
// => [2, 3, 4]
Array.prototype.reduce
コールバックを受け取り、配列の各要素にそのコールバックを適用し、結果を次の呼び出しに引き渡します。
[1, 2, 3].reduce(function (runningSum, element) {
return runningSum + element;
}, 0);
// => 6