Привет!
В сегодняшнем блоге я собираюсь научить выполнять блокировку или выполнять асинхронные вызовы в javascript.
Программирование, в котором строки кода выполняются таким образом, что когда одна строка кода выполняются, то следующие строки должны ждать выполнения, это называется Синхронное программирование. Его также называют «блокирующим программированием».

Возьмем пример:
console.log('A');
console.log('B');
В этом примере выполняется первая инструкция, а вторая инструкция должна подождите, пока 1-й завершит свое выполнение.
Таким образом, результат будет напечатан следующим образом:
A
B

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

Возьмем и этот пример:
console.log('A');
setTimeout(()=›{
console.log('async function');
},2000);
console.log('B');

Я имитировал вызов API, используя функцию setTimeout. Эта функция будет регистрировать «асинхронную функцию» через две секунды после вызова этой функции.
Как вы думаете, что будет на выходе этой функции. Что ж, на всех традиционных языках in должно выглядеть так:

A
асинхронная функция
B
Но в javascript вывод:
A
B
асинхронная функция

Как я уже говорил вам ранее, если вызывается неблокирующая/асинхронная функция, она планирует выполнение задачи в будущем. Поскольку задача запланирована на будущее, строка кода под этой функцией выполняется сразу.

Теперь, что, если мы хотим, чтобы значения возвращались этой функцией, и использовали их в коде ниже, написанном этой функцией.
console.log("Before");
const user = getUser();
console.log(пользователь);
console.log("после");

function getUser()
{ setTimeout(() =›{
console.log(“Чтение пользователя из базы данных”);
return { id: 1, gitHubUsername: “usman-afzal” };
}, 2000);}

Вывод будет
До
undefined
После
Чтение пользователя из базы данных
{ id: 1, gitHubUsername: «usman-afzal» }
Потому что этот пользовательский объект недоступен в тот момент, когда мы пытаемся получить к нему доступ.

Методы блокировки:
Так как же мы можем получить доступ к этому объекту в основной программе? Для этого есть три шаблона работы с асинхронным кодом:
обратный вызов
обещание
асинхронный/ожидание

  1. Async/await:
    Что, если мы напишем асинхронный код как синхронный код. Это будет намного лучше. Это возможно с помощью async и await. В этом методе мы украшаем асинхронную функцию ключевым словом async и пишем ключевое слово await перед вызовом этой функции:
    async function user() {
    try {
    const u = await getUser() ;
    }
    catch (ошибка) {
    console.log(err);
    }
    }
    user();
    function getUser(id) {
    return new Promise((resolve, reject) =› {
    setTimeout( () =› {
    console.log («Чтение пользователя из базы данных»);
    reject({ id: 1, gitHubUsername: «usman-afzal-brainx» });
    } , 2000);
    });
    }
    Async и await — это синтаксический сахар над промисами, и с его помощью мы можем писать асинхронный код как код синхронизации.
    При использовании async/ await, мы должны написать вызов асинхронной функции в блоке try-catch, чтобы, если мы получаем значение, код продолжал выполняться ожидаемым образом, в противном случае выполнение останавливалось, и мы получали ошибку в блоке catch.
  2. Обратные вызовы.
    Обратный вызов — это функция, которая передается в качестве параметра другой функции и вызывает сама себя, когда готов результат асинхронного вызова.
    console.log(“Before ”);
    getUser((user) =› {
    console.log(user);
    });
    console.log(“after”);
    function getUser(callback)
    { setTimeout(() =› {
    console.log("Чтение пользователя из базы данных");
    callback({ id: 1, gitHubUsername : «usman-afzal» });
    }, 5000);
    }
    Это выглядит немного сложно, позвольте мне разобрать его для вас.
    getUser — это асинхронная функция. который получает функцию «обратный вызов». Функция обратного вызова вызывается, когда готов результат асинхронного вызова. Итак, когда вызывается функция getUser, этой функции передается параметр, который является другой функцией. Эта функция является функцией обратного вызова, и эта функция также содержит параметр «пользователь», который будет содержать значение, возвращаемое функцией getUser.
    Теперь вывод этого кода будет следующим:
    до
    после
    { id: 1, gitHubUsername: «usman-afzal» }
    Посмотрите, можем ли мы получить доступ к этому объекту пользователя, который теперь возвращается асинхронной функцией.
    если вы думаете, что, если нам нужно сделать еще один Вызов API после получения пользовательской функции, где мы это делаем, тогда этот код будет помещен в функцию, которая передается в качестве параметра функции обратного вызова. В данном случае вместо console.log('user');
    Позвольте мне продемонстрировать это на примере:
    console.log("До");
    getUser(1, (пользователь) =› {
    console.log(пользователь);
    getRepositories(пользователь, (репозитории) =› {
    console.log(репозитории);
    getCommits(репозитории, (фиксация) =› {
    console.log(фиксация);
    });
    });
    });
    console.log («после») ;
    function getUser(id, callback) {
    setTimeout(() =› {
    console.log("Чтение пользователя из базы данных");
    callback({ id: 1 , gitHubUsername: «usman-afzal» }); }, 2000);
    }
    function getRepositories(username, callback) {
    setTimeout(() =› {
    callback( ["репозиторий 1", "репозиторий 2", "репозиторий 3"]);
    }, 2000);
    }
    function getCommits(repo, callback) {
    setTimeout( () =› { callback([“commit 1”, “commit 2”, “commit 3”]);
    }, 2000);
    }
    В этом примере кода сначала , мы получаем пользователя с помощью асинхронной функции, затем, когда мы получаем пользовательский объект, мы получаем репозитории GitHub этого пользователя, и как только мы получаем это, мы получаем коммиты репо.
    Как вы можете видеть в трех вызовах API, он дошел до этой уродливой глубокой вложенной структуры, которая называется Ад обратных вызовов.
    Чтобы избежать этой проблемы ада обратных вызовов, на помощь приходят именованные функции. .
    Нам придется заменить все анонимные функции именованными функциями. Например, взгляните на параметры вызова функции getCommits. Мы передаем функцию, и в этой функции мы передаем другой параметр фиксации. Мы должны изменить эту анонимную функцию на именованную функцию. Назовем эту функцию displayCommits и поместим в нее весь код анонимной функции.
    function displayCommits(commits, callback) {
    console.log(commits);
    }
    Общая структура приведенного выше кода будет выглядеть так после изменения этой функции
    console.log("До");
    getUser(1, (user) =› {
    console.log( user);
    getRepositories(user, (repositories) =› {
    console.log(repositories);
    getCommits(repositories, displayCommits);
    });
    });
    console.log(“после”);
    function displayCommits(commits, para) {
    console.log(commits);
    }
    function getUser(id, callback) {
    setTimeout(() =› {
    console.log («Чтение пользователя из базы данных»);
    callback ({ id: 1, gitHubUsername: «usman-afzal» });
    }, 2000);
    }
    function getRepositories(username, callback) {
    setTimeout(() =› { callback(["repo 1", "repo 2", "repo 3"]);
    }, 2000);
    }
    function getCommits(repo, callback) {
    setTimeout(() =› {
    callback([“commit 1”, “commit 2”, «commit 3»]);
    }, 2000);
    }
    Теперь продолжайте делать со всеми анонимными функциями, пока они не закончатся. Код будет выглядеть намного лучше и чище, чем раньше. Позвольте мне сделать это для вас прямо сейчас.
    console.log("До");
    getUser(1, displayUser);
    console.log("после");
    function displayUser(user) {
    console.log(user);
    getRepositories(user, displayRepositories);
    }
    function displayRepositories(repositories) {
    console.log(repositories);
    getCommits(repositories, displayCommits);
    }
    function displayCommits(commits) {
    console.log(commits);
    }
    function getUser(id , callback) { setTimeout(() =› {
    console.log («Чтение пользователя из базы данных»);
    callback({ id: 1, gitHubUsername: «usman-afzal» }); < br /> }, 2000);
    }
    function getRepositories(username, callback) {
    setTimeout(() =› { callback([“repo 1”, “repo 2”, “ репозиторий 3”]);
    }, 2000);
    }
    function getCommits(repo, callback) {
    setTimeout(() =› {
    callback([ «commit 1», «commit 2», «commit 3»]);
    }, 2000);
    }
    Теперь мы видим, что структура значительно улучшилась, увеличив также читабельность кода.
    Есть лучший способ справиться с асинхронными вызовами, и это обещания. Давайте посмотрим на них подробно.
  3. Обещания.
    Обещание — это объект, который содержит конечный результат асинхронной операции. Когда асинхронная операция завершается, она может привести либо к значению, либо к ошибке. Обещание обещает вам, что оно даст вам результат асинхронной операции.
    Этот объект может находиться в трех состояниях. Когда мы создаем обещание, оно находится в состоянии ожидания. В этот момент он запустит некоторые асинхронные операции. Когда результат готов, обещание может быть выполнено, что означает, что асинхронная операция завершена успешно, и мы получим значение, иначе, если что-то пойдет не так во время выполнения этой асинхронной операции, наше обещание будет в отклоненном состоянии. В этом случае мы получим некоторые ошибки.
    Создать промис
    const p = new Promise(function(resolve, reject){});
    При создании промиса мы передаем функция, которая имеет 2 параметра: разрешить и отклонить.
    Давайте посмотрим на пример обещания:
    const promise = new Promise((resolve, reject) =› {
    // запускаем какой-то асинхронный вызов< br /> setTimeout(() =› { resolve(1);
    }, 2000);
    });
    promise.then((res) =› console.log(res) );
    Когда обещание разрешается, мы вызываем функцию разрешения и передаем ей значение и получаем значение в свойстве «тогда» этого обещания, в противном случае мы вызываем метод отклонения и получаем отклонение в свойстве catch. Посмотрим, что это тоже:
    const promise = new Promise((resolve, reject) =› {
    // запускаем какой-то асинхронный вызов
    setTimeout(() =› {
    reject(new Error(“сообщение”));
    }, 2000);
    });
    promise.catch((err) =› console.log(err.message));
    Мы можем использовать .then и .catch одновременно. Я просто разделил их, чтобы вы могли лучше понять.
    promise .then((res) =› console.log(res)) .catch((err) =› console.log(err.message));
    Я собираюсь написать приведенный выше адский код обратного вызова, используя promises
    console.log("Before");
    getUser(1)
    .then((user) => getRepositories(user ))
    .then((repositories) =› getCommits(repositories[0]))
    .then((commits) =› console.log(commits));
    console.log( "после");
    function getUser(id) {
    return new Promise((resolve, reject) =› {
    setTimeout(() =› {
    console.log(“Чтение пользователя из база данных");
    resolve({ id: 1, gitHubUsername: "usman-afzal-brainx" });
    }, 2000);
    });
    }
    function getRepositories(username) {
    return new Promise((resolve, reject) =› {
    setTimeout(() =› {
    resolve([“repo 1”, “repo 2 », «репозиторий 3»]);
    }, 2000);
    });
    }
    function getCommits(repo) {
    return new Promise((resolve , reject) =› {
    setTimeout(() =› {
    resolve([“commit 1”, “commit 2”, “commit 3”]);
    }, 2000);
    });
    }
    Видите, так намного проще.

Ладно, это так, ребята. Большое спасибо за то, что все это время были со мной. Я надеюсь, что эта статья поможет вам в чем-то. Хорошего дня!