Поняття callback-функцій в JavaScript

41

Від автора: слово колбек, один з найскладніших для розуміння аспектів JavaScript, часто згадується в контексті функцій і подій. Що таке колбэки, і як вони працюють?

Ви, швидше за все, вже знайомі з колбэками. Наприклад, вони часто зустрічаються в обробниках подій:

button.addEventListener. («click», function() {
… якась дія
})

Така callback-функція анонімна і є замиканням. На колбэки можна посилатися через вираження функцій або обгорткові функції.

Навіщо потрібні callback-функції?

JavaScript – мова програмування, що працює з подіями: код виконується в порядку виникнення подій, але результат обчислюється не обов’язково за порядком у коді. Тобто код:

function first() {
…do something that takes a lot of calculation…
console.log(«First»);
}
first();

Роздрукує слово First в консолі після обчислень. Я я спізнюся цю функцію і створю другу, яка буде виконуватися відразу ж:

function first() {
setTimeout(function() { console.log(«First»); }, 1000);
}
function second(){
console.log(«Second»);
}
first();
second();

Результат в консолі буде відрізнятися від очікуваного:

Second
First

Чому? Під час виконання JS знаходить функцію first() і виконує її. Потім без пауз він переходить на другу функцію і запускає її. JS ніколи не зупиняється і шукає, що йому ще виконати. Ось чому в сучасних браузерах він так швидко працює.

Важливо відзначити, що колбек – це лише певний спосіб оголошення функцій в JS. Явного типу callback-функції не існує. Колбэки з’явилися в ES5 (попередній JS стандарт) і JQuery. На даний момент вони вважаються нормальною технікою програмування.

Покращуємо колбек-функції

У випадку з першим прикладом з обробником події, ми чекали, поки завершиться подія click, і тільки потім виконували залишився код. Однак якщо ви робите щось одне, набагато краще буде замінити колбек на названу функцію:

function makeMenu() {
… do something …
}
button.addEventListener. («click», makeMenu);

Результат буде той же, але так код стає більш абстрактним, а функцію makeMenu тепер можна повторно використовувати в інших частинах скрипта. Виникає одна можлива проблема. Якщо у функцію додати параметри, функція може спрацьовувати миттєво і без події кліку:

function makeMenu(param1) {
console.log(«Clicked»);
}
button.addEventListener. («click», makeMenu(param1));

Результат в консолі без події кліку:

Clicked

Іншими словами, JS запускає подія без якої-небудь дії. Виправити це можна, повернувшись до формального запису колбек-функцій:

function makeMenu(param1) {
console.log(«Clicked»);
}
button.addEventListener. («click», function() { makeMenu(param1) } );

Або ж для параметрів можна використовувати .bind():

button.addEventListener. («click», function() { makeMenu.bind(null, param1) } );

Перший приклад можна скоротити за допомогою функції-стрілки в ES6:

button.addEventListener. (‘click’, () => makeMenu)

У наступній статті я більш детально розповім про функції-стрілки. Також у наступній статті я детально розберу .bind() і просунуті можливості колбек-функцій.

У вас може закрастися підозра, що зчіпка подій за допомогою декількох колбек-функцій може сильно ускладнити код JS і заплутати спадкування. Ви праві. На сайті Callback Hell ви знайдете кілька хороших порад по роботі зі зв’язкою подій. У наступних статтях ми будемо приділяти увагу цій проблемі.

Висновок

По суті, колбек-функції являють собою спосіб контролювати порядок виконання коду в JS, спосіб домогтися виконання коду в логічному порядку. Такі функції часто називають асинхронним JS: функція передається у вигляді параметра і каже «зроби це в майбутньому». Наскільки у майбутньому або умови виконання переданої функції описуються в колбек-функції. У ES6 такий підхід використовують для промисов.

JS пронизаний колбек-функціями, які є невід’ємною частиною мови. window.requestAnimationFrame() – приклад колбек-функції, яка виконується, як тільки браузера визначає, що він готовий до візуалізації контенту на екран, що забезпечує плавність анімації.

Постійна робота JS (завжди чекає події і миттєво реагує на все) також впливає на продуктивність, особливо часто-запускаються події типу прокрутки вікна, зміни розміру вікна при роботі з деякими полями типу range. Я покажу ці приклади у статті, де ми будемо штучно занижувати продуктивність браузера.

Подієвий характер JS частково контролюється такими поняттями, як замикання, область видимості і контекст, про які я розповім в окремих статтях.