_توابعی که بهعنوان آرگومان به تابعهای دیگر داده میشوند، «توابع callback» نامیده میشوند. سپس میتوان تابع callback را فراخوانی کرد تا اقدامی پس از آن به راه بیفتد. اغلب از callbackها برای رسیدگی به نتیجهی کاری که انجام شده، یا برای رسیدگی به یک اقدام هنگام رخ دادن یک رویداد استفاده میشود. از توابع callback میتوان در برنامهنویسی همگام و ناهمگام بهره برد.
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
میتوانید callbackها را بهصورت یک عبارت تابع هم بنویسید:
applySideLength(function squarePerimeter(side) {
return side * 4;
});
این الگوی سودمندی در JavaScript است، چون JavaScript بهعنوان یک محیط اجرای تکنخی طراحی شده است که در آن در هر لحظه تنها یک فراخوانی تابع میتواند اجرا شود. در حین اجرا، محیط اجرا نمیتواند به رویدادهای دیگر پاسخ دهد یا اجرا را ادامه دهد تا زمانی که تابع بازگردد.
بسیاری از فراخوانیهای API (توابع ورودی/خروجی، تایمرها و شنوندههای رویداد) از سازوکاری ناهمگام استفاده میکنند تا فراخوانی تابع جاری را تا کامل شدن کار کنار بگذارند. پس از کامل شدن، یک تابع callback در صف پیامها قرار میگیرد تا وقتی محیط اجرا میان فراخوانیهای تابع قرار دارد، پیامها با فراخوانی تابع callback پردازش شوند.
استفاده از توابع callback همچنین سودمند است، چون آنها میتوانند به متغیرهایی در حوزهی بستار خود ارجاع دهند که برای تابعی که بعداً در آن فراخوانی میشوند در دسترس نیست.
گردانندههای رویداد یک مورد استفادهی رایج برای callbackها در JavaScript هستند. رویدادهای مرورگر مانند 'onload' یا 'onclick' نشانههایی هستند که میتوانند باعث فراخوانی توابع شوند. متد addEventListener در یک شیء DOM [مدل شیء سند یک تابع callback را ثبت میکند که هنگام «شنیدن» رخ دادن یک رویداد فراخوانی میشود.
document.addEventListener('onload', function () {
alert('The webpage has now been loaded');
});
در Node.js، توابع callback برای کنترل جریان برنامه از یک قرارداد پیروی میکنند. آنها از این الگو پیروی میکنند: آرگومان اول تابع callback ممکن است یک Error یا null دریافت کند؛ آرگومانهای دوم و بعدی دادهای را دریافت میکنند که تابع فراخوانیکننده برای فرستادن آن در نظر گرفته شده است.
اگر خطایی رخ دهد، ممکن است آرگومانهای دوم و بعدی وجود نداشته باشند، پس نمیتوانید روی وجودشان حساب کنید.
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 از توابع callback برای تعریف رفتار خود بهره میبرند:
Array.prototype.forEach:
یک callback میپذیرد و آن را روی هر عنصر آرایه اعمال میکند.
[1, 2, 3].forEach(function (element) {
doSomething(element);
});
// => doSomething() is invoked 3 times, once with each element
Array.prototype.map
یک callback میپذیرد، آن را روی هر عنصر آرایه اعمال میکند و از نتیجه برای ساختن یک آرایهی جدید استفاده میکند.
[1, 2, 3].map(function (element) {
return element + 1;
});
// => [2, 3, 4]
Array.prototype.reduce
یک callback میپذیرد، آن را روی هر عنصر آرایه اعمال میکند و نتیجه را به فراخوانی بعدی میفرستد.
[1, 2, 3].reduce(function (runningSum, element) {
return runningSum + element;
}, 0);
// => 6