Меню

Callbacks — функции обратного вызова в JS

05.07.2018 - java script, ЯП

Callbacks

Вот у нас есть пример асинхронного кода.

console.log('Before');
const user = getUser(1);
console.log(user); //undefined
console.log('After');

function getUser(id) {
    setTimeout(() => {
        console.log("Get user " + id);
        return {
            id,
            gitHubUsername: 'igenex'
        }
    }, 1000);
    return 1;
}

Посмотрим, как с помощью колбэков получить объект из функции getUser.
Сначала удалим за ненадобностью return который возвращает единицу в самом низу. Теперь добавим второй параметр в нашу функцию getUser и назовем его callback.

callback это функция, которая будет выполнена, как только результат будет готов.

function getUser(id, callback) {
    setTimeout(() => {
        console.log("Get user " + id);
        callback( {
            id,
            gitHubUsername: 'igenex'
        });
    }, 1000);
    return 1;
}

Мы передадим наш объект в качестве аргемента нашему колбэку.
Теперь мы добавим второй аргумент при вызове самой этой функции.

getUser(1, user => console.log('User: ', user));

Это и есть пример callback функции. Когда результат готов, эта функцию будет вызвана с результатом.

Давайте представим, что как только получили пользователя из базы данных, мы вызываем API githubа, чтобы получить список рипозиториев полученного из базы юзера.

console.log('Before');
const user = getUser(1, user => {
    getRepositories(user.gitHubUsername, repo => console.log(repo));
});
console.log('After');

function getUser(id, callback) {
    setTimeout(() => {
        console.log("Get user " + id);
        callback( {
            id,
            gitHubUsername: 'igenex'
        });
    }, 2000);
}

function getRepositories(user, callback) {
    setTimeout(() => {
        callback(['repo1','repo2','repo3']);
    }, 2000)
}

Callback Hell

Чтомы видим в последнем примере? Вложенную структуру. Колбэк в колбэке. В реальном приложении эта вложенность может достигать внушительных размеров.

const user = getUser(1, user => {
    getRepositories(user.gitHubUsername, repo => {
        console.log(repo);
        getCommits(repo, commits => {
            console.log(commits);
        });
    });
});

Named functions to Rescue

Посмотрим простое решение для проблемы Callback Hell.

Техника, которую мы собираемся использовать, это заменить анонимные функции на именованные.

Начнем с самой вложенной функции. Создадим функцию displayCommits. И подставим её вместо анонимной функции. Обратите внимание, что мы не вызываем эту функцию, а передаем по ссылке.

console.log('Before');
const user = getUser(1, getRepositories);
console.log('After');

function getCommits(repos) {
    getCommits(repos, displayCommits);
}

function getRepositories(user) {
    getRepositories(user.gitHubUsername, getCommits);
}

function displayCommits(commits) {
    console.log(commits);
}

function getUser(id, callback) {
    setTimeout(() => {
        console.log("Get user " + id);
        callback( {
            id,
            gitHubUsername: 'igenex'
        });
    }, 2000);
}

function getRepositories(user, callback) {
    setTimeout(() => {
        callback(['repo1','repo2','repo3']);
    }, 2000)
}

Изначально код может казаться немного сбивающим, потому что например в функции getRepositories мы вызываем другую функцию getRepositories. Но эти функции разные. Потому что первая принимает объект user, в то время как вторая принимает строку в качестве первого аргумента, и колбэк в качестве второго аргумента.

Метки: , ,

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *