Обратные вызовы являются важной частью понимания JavaScript, особенно при работе с асинхронным кодом. Давайте рассмотрим основы обратных вызовов за 5 минут на нескольких примерах!
Что такое функции обратного вызова?
Одним из наиболее уникальных аспектов JavaScript является отношение к функциям. Функции считаются «гражданами первого класса». Это имеет несколько различных последствий.
- функции являются объектами
- вы можете присвоить функцию переменной
- функции можно передавать в качестве параметра функции.
Последний пункт выделен жирным шрифтом, потому что он очень важен для идеи обратных вызовов.
Функции обратного вызова — это функции, которые передаются в качестве параметра другой функции.
Базовый обратный вызов с setTimeout
Один из первых случаев, когда разработчики JavaScript сталкиваются с функцией обратного вызова, — это использование функции setTimeout()
. Вот простой пример.
setTimeout(() => {
console.log("Hello")
},100)
В этом случае мы говорим JavaScript вызвать нашу функцию обратного вызова после ожидания в течение 100 мс. Функция setTimeout()
принимает два параметра: функцию обратного вызова и число тайм-аута в миллисекундах. Мы можем сделать это более очевидным, создав отдельную функцию полностью, вместо того чтобы использовать встроенную анонимную функцию.
//this is the callback function
const timeoutCallback = () => {
console.log("Hello")
}
setTimeout(timeoutCallback, 100)
Это работает точно так же, как и предыдущий фрагмент, но теперь мы выделили функцию более четко.
Обратные вызовы в функциях массива
Если вы много писали на JavaScript за последние несколько лет, то наверняка знакомы с такими функциями массивов, как map()
, reduce()
, filter()
, forEach()
и т. д. Каждая из этих функций использует обратные вызовы. Каждая из них перебирает массив и вызывает функцию обратного вызова для каждого элемента. Вот пример с forEach()
.
const names = ['james', 'jess', 'lily', 'sevy']
names.forEach((name) => {
console.log(name)
});
В этом случае функция обратного вызова определена в строке и принимает параметр, который является отдельным именем из массива names
. Затем она записывает это имя в консоль. Этот пример может показаться простым, но давайте посмотрим, что происходит за кулисами.
Создание forEach() с нуля с помощью обратных вызовов
Создание функций JavaScript с нуля всегда было для меня удивительным учебным упражнением, поэтому давайте попробуем сделать это здесь. Давайте создадим собственную версию функции forEach()
, чтобы получить более четкое представление о том, как работают обратные вызовы.
Создадим новую функцию myForEach()
, которая принимает два параметра, массив и функцию обратного вызова.
const myForEach = (arr, cb) => {
}
Внутри функции мы можем создать цикл for для итерации по массиву и получения доступа к каждому элементу.
const myForEach = (arr, cb) => {
for (let i = 0; i < arr.length; i++) {
const element = arr[i];
}
}
Отсюда мы вызовем функцию обратного вызова и передадим отдельный элемент в качестве параметра.
const myForEach = (arr, cb) => {
for (let i = 0; i < arr.length; i++) {
const element = arr[i];
cb(element)
}
}
Вот и все. Вот, по сути, то, что все функции массива делают за кулисами. Создание подобных примеров всегда помогало моему пониманию, так что, надеюсь, это поможет и вам!
Асинхронные функции обратного вызова
Примеры функций массива, показанные выше, имеют дело с синхронным кодом, поэтому давайте рассмотрим пример того, как это работает с асинхронным кодом. Давайте воспользуемся встроенной функцией fetch()
в JavaScript для запроса данных из FREE PokeAPI.
В этом случае мы сделаем запрос на получение данных из PokeAPI для покемона с идентификатором 56 (вы знаете, какой это покемон? 👀).
fetch(`https://pokeapi.co/api/v2/pokemon/${id}`)
.then(res => {
return res.json()
})
.then(data => {
console.log(data)
})
Fetch возвращает обещание, поэтому мы должны использовать .then()
`, чтобы дождаться ответа. Затем мы преобразуем данные в JSON, который возвращает еще одно обещание. Наконец, мы выводим данные о покемонах. Мы передаем функцию обратного вызова каждому экземпляру
.then()`. Это полезно, потому что мы продолжаем выполнять другой код, пока выполняется запрос, а не ждем все время, пока данные будут возвращены.
Завершение
Обратные вызовы являются неотъемлемой частью JavaScript. Поток и использование могут показаться сложными поначалу, но, надеюсь, с помощью нескольких примеров все стало проще!