Що таке callback API




Що таке callback API



Що таке callback-функція JavaScript?

Простими словами: коллбек - це функція, яка повинна бути виконана після того, як інша функція завершила виконання (звідси і назва callback - функція зворотного виклику).

Трохи складніше: У JavaScript функції це об'єкти. Тому функції можуть приймати інші функції як аргументи, а також повертати функції як результат. Функції, які це вміють, називають функціями вищого порядку. А будь-яка функція, яка передається як аргумент, називається callback-функцією.

Навіщо потрібні коллбеки?

З однієї простої причини: JavaScript - це подієво-орієнтована мова. Тому замість того, щоб чекати на відповідь для подальшого виконання програми, JavaScript продовжить виконання, одночасно чекаючи інших подій. Давайте розберемо простий приклад:

const first
=
()
=>

console.log(1);
>;
const
second
=
()
=>

console.log(2);
>;
first();
second();

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

Поки що все зрозуміло. Але що, якщо функція first містить код, який не може виконатися негайно? Наприклад, робота з API, де ми надсилаємо запит і маємо чекати відповіді. Щоб змоделювати таку ситуацію, ми використовуємо функцію setTimeout, яка викликає функцію після заданого проміжку часу. Ми відстрочимо виконання функції на 500 мілісекунд, начебто це запит до когось API. Тепер код виглядатиме так:

const first
=
()
=>

// Ніби запит до API
setTimeout(()
=>

console.log(1);
>,
500
);
>;
const
second
=
()
=>

console.log(2);
>;
first();
second();

Неважливо, чи ви розумієте зараз, як працює setTimeout() . Основна ідея – тепер ми відклали виконання команди console.log(1) на 500 мілісекунд. І що тепер виведе наша програма?

Хоча ми, як і раніше, викликаємо функцію першої першої, її висновок з'явився другим, після виведення функції second . Але JavaScript не порушує порядок виклику функцій, він просто не чекає відповіді від функції first, а відразу рухається далі – до функції second.

Тому не можна просто викликати функції у потрібному порядку і сподіватися, що вони у будь-якому випадку виконаються у тому порядку. Коллбеки дозволяють нам бути впевненими в тому, що певний код не почне виконання до того моменту, поки інший код не завершить виконання.

  • Постійна підтримка від наставника та навчального центру
  • Допомога з працевлаштуванням
  • Готове портфоліо до кінця навчання
  • Практика з першого уроку

Ви отримаєте саме ті інструменти та навички, які дозволять вам знайти роботу

Створюємо колбек

По-перше, відкрийте консоль розробника в Google Chrome (Windows: Ctrl + Shift + J) (Mac: Cmd + Option + J), або свій IDE, або просто Repl.it і введіть в консолі наступну функцію:

const doHomework
=
(subject)
=>

alert(`Starting my
$subject>
homework.);
>;

Ми створили функцію doHomework. Наша функція приймає одну змінну - назву предмета, яким ми займатимемося. Викличте функцію, набравши наступний текст у консолі:

doHomework('math');
// Виводить алерт: Starting my math homework.

Тепер давайте додамо до визначення функції ще один параметр, це і буде наш коллбек. Потім викличемо її, визначивши функцію-callback як аргумент:

const doHomework
=
(subject,
callback)
=>

alert(`Starting my
$subject>
homework.);
callback();
>;
doHomework('math',
()
=>

alert('Finished my homework');
>);

Якщо ви введете цей код у консолі, ви отримаєте два алерти один за одним, у першому буде повідомлення про те, що виконання домашнього завдання почалося (Starting my math homework.), а у другому - що ви закінчили виконувати завдання (Finished my homework) .

Однак, коллбеки не обов'язково повинні бути визначені при виклику функції. Вони можуть бути визначені і в іншому місці коду, наприклад:

const doHomework
=
(subject,
callback)
=>

alert(`Starting my
$subject>
homework.);
callback();
>;
const
alertFinished
=
()
=>

alert('Finished my homework');
>;
doHomework('math',
alertFinished);

Таким чином, результат виконання цього коду такий самий, як і в попередньому прикладі, однак сам код трохи інший. Як ви бачите, ми передали функцію alertFinished як аргумент у функцію doHomework під час її виклику.

Перепишемо приклад виклику функції з setTimeout для послідовного виконання функцій:

const first
=
(callback)
=>

// Ніби запит до API
setTimeout(()
=>

console.log(1);
callback();
>,
500
);
>;
const
second
=
()
=>

console.log(2);
>;
first(second);
// 1
// 2

Приклад із реального життя

Минулого тижня я опублікував статтю «Створюємо робота для Твіттера в 38 рядків коду» . Цей код працює завдяки API Twitter. І коли ми робимо запит до API, ми маємо дочекатися відповіді до того, як почнемо виконувати з цією відповіддю якісь дії. Це чудовий приклад того, як у реальному житті виглядає коллбек. Ось як виглядає сам запит:

T.get('search/tweets',
params,
(err,
data,
response)
=>

if
(!err)

// Відбувається якась магія
>
else

console.log(err);
>
>);

T.get просто означає, що ми виконуємо get запит до API Twitter. У запиті три параметри: 'search/tweets' – це адреса (роут) запиту, params – наші параметри пошуку і в кінці передається анонімна функція callback.

Коллбек тут потрібен, тому що нам потрібно дочекатися відповіді від сервера до того, як приступимо до виконання коду. Ми не знаємо, чи успішним буде наш запит чи ні, тому після відправки параметрів пошуку на search/tweets через get-запит, ми просто чекаємо. Як тільки Твіттер відповість, виконається наша callback-функція.Твіттер відправить нам як відповідь або об'єкт err (error – помилка), або об'єкт response. У коллбеку ми можемо через if() перевірити, чи був запит успішним чи ні, а потім діяти відповідно.

  • Вивчіть затребувані JavaScript та TypeScript
  • Навчіться створювати інтерфейси сайтів і додатків.
  • Освойте найпопулярніший фреймворк JavaScript — React
  • Ознайомтеся з мовами веб-розробки HTML та CSS

JavaScript: Що таке функції зворотного дзвінка/Callback

Коли ви починаєте вивчати JavaScript, невдовзі почуєте термін функції зворотного дзвінка . Зворотні виклики - невід'ємна частина моделі виконання JavaScript, і важливо розуміти, що вони являють собою і як працюють.

Що таке зворотні дзвінки JavaScript

У JavaScript Зворотній Дзвінок (або Callback) — це функція, яка передається як аргумент іншої функції. Функція, що отримує зворотний дзвінок, вирішує, чи виконувати зворотний дзвінок і коли:

function
myFunction(callback)


// 1. Щось робить
// 2. Потім здійснює зворотний виклик
callback()
>

function myCallback()
// Робить щось інше
>

myFunction(myCallback);

У наведеному вище прикладі є дві функції myFunction і myCallback. Як випливає з назви, myCallback використовується як функція зворотного дзвінка, і ми передаємо її в myFunction як аргумент. Потім myFunction може здійснити зворотній виклик, коли буде готовий.

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

Навіщо потрібні функції зворотного виклику

Ви часто чутимете, що JavaScrip є однопоточним. Це означає, що він може робити одну річ за один раз.При виконанні повільної операції, такої як отримання даних віддаленого API, це може бути проблематичним. Було б не дуже приємно, якби ваша програма зависла доти, доки дані не будуть повернуті.

Один із способів, яким JavaScript дозволяє уникнути цього вузького місця, – використання зворотного виклику. Ми можемо передати другу функцію як аргумент функції, яка відповідає за вибірку даних. Потім запускається запит на отримання даних, але замість очікування інтерпретатор JavaScript продовжує виконання решти програми. Коли надходить відповідь від API, функція зворотного дзвінка виконується і може виконувати дії з результатом:

function
fetchData(url, cb)


// 1. Виконує запит до API з URL
// 2. Якщо відповідь успішна, виконати зворотній виклик
cb(res);
>

function callback(res)
// Зробити щось із результатом
>

// Зробити щось
fetchData('https://sitepoint.com', callback);
// Зробити щось ще

JavaScript - мова, керована подіями

Ви також почуєте, як люди говорять, що JavaScript - мова керована подіями (event-driven language). Це означає, що він може прослуховувати події та не реагувати на них, продовжуючи виконувати подальший код та не блокуючи свій єдиний потік.

І як це робить? Ви вже здогадалися: зворотні дзвінки.

Уявіть, що ваша програма прив'язує слухач подій до кнопки, а потім сидить і чекає, поки хтось натисне цю кнопку, відмовляючись робити що-небудь ще. Це було б не круто!

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

function
handleClick()


// Робимо щось (наприклад, перевіряємо форму)
// у відповідь натисненням користувачем кнопки
>

document.querySelector('button').addEventListener('click', handleClick);

У наведеному вище прикладі функція handleClick є зворотним викликом, що виконується у відповідь на дію, що відбувається на веб-сторінці (клік по кнопці).

Використовуючи цей підхід, ми можемо реагувати на стільки подій, скільки ми захочемо, залишаючи інтерпретатору JavaScript свободу робити все, що йому потрібно.

Функції першого класу та вищого порядку

Ще пара модних слів з якими ви можете зіткнутися при вивченні зворотних викликів, це функції першого класу і функції вищого порядку. Звучить лякаюче, але це не так.

Коли ми говоримо, що JavaScript підтримує функції першого класу, це означає, що ми можемо поводитися з функціями як зі звичайними значеннями. Ми можемо зберігати їх у змінній. Ми можемо повертати їх із іншої функції. І, як ми вже бачили, ми можемо передавати їх як аргументи.

Що стосується функцій вищого порядку, то це просто функції, які або приймають функцію як аргумент, або повертають функцію як результат. Є кілька нативних функцій JavaScript, що є функціями вищого порядку, наприклад setTimeout. Давайте використовуємо її для демонстрації створення та запуску зворотного дзвінка.

Як створити функцію зворотного дзвінка

Шаблон такий самий як і вище: створіть функцію зворотного виклику та передайте її функції вищого порядку як аргумент:

function
greet()


console.log('Hello, World!');
>

setTimeout(greet, 1000);

Функція setTimeout виконує функцію greet() із затримкою в 1 секунду (1000 мс) та виводить у лог консолі Hello, World! .

Ми також можемо зробити це трохи складніше і передати функції greet() ім'я того, кого потрібно вітати:

function
greet(name)


console.log(`Hello, $name>!`);
>

setTimeout(() => greet('Jim'), 1000);

Зверніть увагу, ми використовували стрілочну функцію, щоб обернути вихідний виклик вітання.Якби цього не зробили, то функція виконувалася б одразу, а не із затримкою.

Як бачите, існують різні способи створення функцій зворотного виклику JavaScript, що підводить нас до наступного розділу.

Різні види функцій зворотного виклику

Почасти завдяки підтримці JavaScript функцій першого класу, існують різні способи оголошення функцій JavaScript і, отже, різні способи їх використання у зворотних викликах.

Давайте розглянемо їх переваги та недоліки.

Анонімні функції JavaScript

До цього часу ми використовували іменовані функції. Зазвичай це вважається гарною практикою, але в жодному разі не є обов'язковою. Розглянемо наступний приклад, у якому функція зворотного дзвінка використовується для перевірки введення кількох форм:

document.querySelector('form').addEventListener('submit',
function(e)


e.preventDefault();
// Виконуємо певну перевірку даних
/ / Якщо все виглядає нормально, то.
this.submit();
>);

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

Стрілочні функції

Стрілецькі функції були представлені в ES6. Завдяки лаконічному синтаксису і тому, що вони мають неявне значення, що повертається, вони часто використовуються для виконання простих однострочників, як у наступному прикладі, який відфільтровує повторювані значення з масиву:

const arr  =
[1,
2,
2,
3,
4,
5,
5];

const unique = arr.filter((el, i) => arr.indexOf(el) === i);
// [1, 2, 3, 4, 5]

Майте на увазі, вони не прив'язують власне значення цього, а успадковують його від своєї батьківської області.Це означає, що в попередньому прикладі ми не змогли б використовувати стрілочну функцію для надсилання форми:

document.querySelector('form').addEventListener('submit',
(e)
=>


.
// Uncaught TypeError: this.submit не є функцією `this`
// свідчить про об'єкт window, а чи не на form.
this.submit();
>);

Стрілецькі функції - один з моїх улюблених доповнень до JavaScript за останні роки, і розробники повинні з ним ознайомитися.

Іменовані функції

Є два способи створення іменованих функцій у JavaScript: функціональні вирази та оголошення функцій. Обидва можуть використовуватись із зворотними викликами.

Оголошення функції включає створення функції з використанням ключового слова function та присвоєння її імені:

function
myCallback()
.
>

setTimeout(myCallback, 1000);

Функціональне вираз включає створення функції та присвоєння її змінної:

const
myCallback
=
function()

.
>;

setTimeout(myCallback, 1000);
const
myCallback
=
()
=>

.
>;

setTimeout(myCallback, 1000);

Ми також можемо визначити ім'я анонімної функції, оголошеної за допомогою ключового слова function :

setTimeout(function
myCallback()

.
>,
1000);

Перевага такого імені функції зворотного виклику полягає в тому, що це допомагає при налагодженні. Давайте зробимо так, щоб функція видавала помилку:

setTimeout(function
myCallback()

throw
new
Error('Boom!');
>,
1000);


// Uncaught Error: Boom!
// myCallback file:///home/jim/Desktop/index.js:18
// setTimeout handler* file:///home/jim/Desktop/index.js:18

Використовуючи іменовану функцію, ми можемо побачити де саме сталася помилка. Однак подивіться, що відбувається, коли ми видаляємо ім'я:

setTimeout(function()

throw
new
Error('Boom!');
>,
1000);


// Uncaught Error: Boom!
// file:///home/jim/Desktop/index.js:18
// setTimeout handler* file:///home/jim/Desktop/index.js:18

Це не відіграє особливої ​​ролі в маленькому прикладі, але зі зростанням вашої кодової бази про це слід пам'ятати. Існує правило ESLint для забезпечення такої поведінки.

Найпоширеніші варіанти використання функцій зворотного дзвінка JavaScript

Варіанти використання функцій зворотного виклику JavaScript широкі та різноманітні. Як ми бачили, вони корисні при роботі з асинхронним кодом (наприклад, запит Ajax) і при реагуванні на події (наприклад, відправлення форми). Тепер давайте подивимося ще на кілька місць, де ми знаходимо зворотні виклики.

Методи масиву

Ще одне місце, де ви зіткнетеся зі зворотними викликами, - це робота з методами масиву JavaScript. Це те, чим ви займатиметеся все більше і більше в міру просування шляхом програмування. Наприклад, припустимо, що ви хочете підсумовувати всі числа в масиві. Розглянемо цю наївну реалізацію:

const arr =
[1,
2,
3,
4,
5];

let tot = 0;
for(let i=0; iarr.length; i++)
tot += arr[i];
>
console.log(tot); //15

І хоча це працює, коротша реалізація може використовувати Array.reduce , який, як ви вже здогадалися, використовує зворотний виклик для виконання операції над усіма елементами масиву:

const arr =
[1,
2,
3,
4,
5];

const tot = arr.reduce((acc, el) => acc + el);
console.log(tot);
// 15

Node.js

Також слід зазначити, що Node.js і вся його екосистема значною мірою залежить від коду, заснованого на зворотних викликах. Наприклад, ось Node.js версія канонічного Hello, World!

const http =
require('http');


http.createServer((request, response) =>
response.writeHead(200);
response.end('Hello, World!');
>).listen(3000);

console.log('Server running on http://localhost:3000');

Незалежно від того, використовували ви коли-небудь Node чи ні, сподіваюся, цей код буде простим для розуміння.По суті, нам потрібен модуль http Node і викликається його метод createServer, якому передаємо анонімну стрілочну функцію. Ця функція викликається щоразу, коли Node отримує запит на порт 3000, і він відповідає статусом 200 та текстом Hello, World!

Node також реалізує патерн, відомий як зворотні дзвінки з першою помилкою. Це означає, що перший аргумент зворотного дзвінка зарезервований для об'єкта помилки, а другий аргумент зворотного дзвінка зарезервований для будь-яких успішних даних відповіді.

Ось приклад із документації Node, що показує, як читати файл:

const fs =
require('fs');

fs.readFile('/etc/hosts', 'utf8', function (err, data)
if (err)
return console.log(err);
>
console.log(data);
>);

Ми не хочемо заглиблюватися в Node у цьому посібнику, але сподіваємося, що тепер такий код буде набагато легше читати.

Синхронні та Асинхронні Зворотні дзвінки

Чи виконується зворотний дзвінок синхронно або асинхронно, залежить від функції, яка його викликає. Давайте розглянемо кілька прикладів.

Синхронні функції зворотного дзвінка

Коли код синхронний, він виконується зверху вниз, рядок за рядком. Операції виконуються одна за одною, при цьому кожна операція очікує завершення попередньої. Ми вже бачили приклад вище синхронного зворотного виклику функції Array.reduce .

Щоб ще більше проілюструвати це, ось демонстрація, в якій використовується як Array.map , так і Array.reduce для обчислення максимального чистого списку чисел, розділених комами:

Основна дія відбувається тут:

const highest = input.value 
.replace(/\s+/, '')
.split(',')
.map((el) => Номер(el))
.reduce((acc,val) => (acc > val) ? acc : val);

Рухаючись зверху вниз, робимо таке:

  • Отримуємо введення користувача.
  • Видаляємо всі прогалини.
  • За допомогою split створюємо масив рядків використовуючи , як роздільник.
  • Використовуючи map, перетворюємо кожен елемент масиву в число.
  • Використовуємо reduce для перебору масиву та пошуку найбільшого числа.

Чому б не пограти з кодом на CodePen? Спробуйте змінити зворотний дзвінок для отримання іншого результату (наприклад, для пошуку найменшого числа або всіх непарних чисел тощо).

Асинхронні функції зворотного виклику

На відміну від синхронного коду, асинхронний код JavaScript не буде виконуватися зверху донизу, рядок за рядком. Натомість асинхронна операція зареєструє функцію зворотного виклику, яка буде виконана після її завершення. Це означає, що інтерпретатор JavaScript не потребує завершення асинхронної операції, а замість цього він може виконувати інші завдання під час її виконання.

Одним з основних прикладів асинхронного коду є отримання даних віддаленого API. Давайте подивимося на приклад і розберемо, як він використовує зворотні виклики.

Основна дія відбувається тут:

fetch('https://jsonplaceholder.typicode.com/users')

.then(response => response.json())
.then(json =>
const names = json.map(user => user.name);
names.forEach(name =>
const li = document.createElement('li');
li.textContent = name;
ul.appendChild(li);
>);
>);

Код у наведеному вище прикладі використовує FetchAPI для надсилання запиту списку фіктивних користувачів у фейковому JSON API. Як тільки сервер повертає відповідь, ми запускаємо нашу першу функцію зворотного дзвінка, яка намагається перетворити цю відповідь на JSON. Після цього розпочинається друга функція зворотного дзвінка, яка створює список імен користувачів і додає їх до списку.Зверніть увагу, що всередині другого зворотного дзвінка ми використовуємо ще два вкладені зворотні дзвінки для роботи з вилучення імен і створення елементів списку.

Ще раз, я порадив би вам пограти з кодом. Якщо ви ознайомитеся з документацією API, ви знайдете безліч інших ресурсів, які ви можете отримати і використовувати.

Що потрібно знати під час використання зворотних викликів

Зворотні дзвінки існують у JavaScript давно, і вони не завжди можуть підходити для того, що ви намагаєтеся зробити. Розглянемо кілька речей, про які потрібно знати.

Уникайте пекла зворотних викликів (Callback Hell)

У прикладі коду, наведеному вище, ми бачили, що зворотні виклики можна вкладати один в одного. Це часто зустрічається при роботі з асинхронними функціями, що залежать один від одного. Наприклад, ви можете одержати список фільмів одним запитом, а потім використовувати цей список для отримання постера для кожного окремого фільму.

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

fetch('. ')

.then(response => response.json())
.then(json =>
// Робимо якусь обробку
fetch('. ')
.then(response => response.json())
.then(json =>
// Робимо ще обробку
fetch('. ')
.then(response => response.json())
.then(json =>
// Робимо іншу обробку
fetch('. ')
.then(response => response.json())
.then(json =>
// Робимо ще якусь обробку
>);
>);
>);
>);

Це лагідно називають пеклом зворотних викликів. Але цього можна уникнути.

Віддайте перевагу більш сучасним методам управління потоком

Хоча зворотні виклики є невід'ємною частиною JavaScript, у пізніших версіях мови були додані покращені методи керування потоком.

Наприклад, Promise та async.await забезпечують більш чистий синтаксис для роботи з вказаним вище кодом. Але це виходить за межі цієї статті.

Висновок

У цій статті ми розглянули, що таке зворотні дзвінки. Ми розглянули основи моделі JavaScript, як зворотні виклики вписуються в цю модель і чому вони необхідні. Ми також розглянули, як створювати та використовувати зворотні дзвінки, різні види зворотних дзвінків і коли їх використовувати. Тепер у вас має бути чітке уявлення про роботу зі зворотними викликами JavaScript і можливість використовувати ці методи у своєму власному коді.

Схожі статті

  • Що таке Ципру
  • Що таке режим Atti для дронів Drones Cameras
  • Що таке Адамове яблуко у чоловіків
  • Що таке добори на міжкімнатні
  • Що таке дека на газонокосарці
  • Що таке код помилки 601
  • Що таке Жилка яловича
  • Що таке фонетична норма
  • Недавні статті

  • Як бродить зернова брага
  • Що робити якщо не засмагаєш на сонці чому засмага погано лягає на шкіру або перестає прилипати
  • Як швидко зняти гель лак без апарату
  • Як робиться Каті голови
  • Яка гребінець краще для об'єму
  • Чим роблять м'яку покрівлю
  • Чи можна залишати крем для обличчя на ніч
  • Де знаходиться датчик селектора
  • географія нашої діяльності
    вулиця Драгоманова, 27
    вул. Курчатова 1Б
    вул. Міцкевича 130
    вул. Лабунського, 1
    вул. Макарова-Пржевальського
    вул. Толстого 10
    вул. Грушевського 28
    вул. Перший промінь (Черняхівського)
    напишіть нам

    сообщение успешно отправлено
    x