Async/await в javascript

В этом уроке вы узнаете, как использовать Async/Await в JavaScript.

Но прежде чем мы начнем, мы должны понять несколько тем, таких как:

  • Event loops (циклы событий)
  • Callbacks (обратные вызовы)
  • Promises (обещания)

Что такое циклы событий в JavaScript?

Циклы событий являются одним из наиболее важных аспектов JavaScript.

JavaScript-это однопоточный язык программирования, который означает, что одновременно может выполняться только одна задача. Он имеет стек вызовов, и весь код выполняется внутри этого стека вызовов. Давайте разберемся на примере:

Циклы

В приведенном выше примере мы видим, что регистрируем два значения в консоли.

Когда First () завершит свое выполнение, он будет извлечен из стека вызовов, а цикл обработки событий перейдет к следующей строке. Следующая строка будет сохранена в стеке вызовов и помечена для выполнения.

Циклы

Наша консоль выдаст следующий результат:

Консоль

Чтобы лучше понять ситуацию, давайте взглянем на другой пример:

console.log('First!');

setTimeout(function second(){
    console.log('Timed Out!')
}, 0000)

console.log('Final!');

Как обычно, наш код переместится в стек вызовов, а цикл обработки событий будет выполняться построчно.

Мы получим «First!» в консоли, и он будет перемещен из стека вызовов.

Теперь цикл обработки событий переместится во вторую строку и поместит ее в стек вызовов. Он встретит функцию setTimeout, которая является задачей макроса, и она будет выполнена в следующем цикле событий.

А теперь вам может быть интересно, что такое макрозадача. Ну, это задача, которая выполняется после всех задач в цикле событий, или, можно сказать, в другом цикле событий. Функции SetTimeout и SetInterval могут быть примером задачи макроса, которая выполняется после завершения всех других задач.

Консоль

Наконец, будет выполнена последняя строка кода. Мы получим First в нашей консоли, затем Final, а затем Timed Out.

Как функции обратного вызова работают в JavaScript?

Функции обратного вызова — это те функции, которые были переданы другой функции в качестве аргумента.

Давайте посмотрим на пример:

const movies = [
{ title: `A New Hope`, body:`After Princess Leia, the leader of the Rebel Alliance, is held hostage by Darth Vader, Luke and Han Solo must free her and destroy the powerful weapon created by the Galactic Empire.`},
{ title: `The Empire Strikes Back`, body: `Darth Vader is adamant about turning Luke Skywalker to the dark side. Master Yoda trains Luke to become a Jedi Knight while his friends try to fend off the Imperial fleet.` }]

function getMovies(){
    setTimeout(() => {
        movies.forEach((movie, index) => {
            console.log(movie.title)
        })
    }, 1000);
}

getMovies();

У нас есть массив, содержащий список фильмов по «Звездным войнам» и функцию getMovies () для получения списка.

Callback

Давайте создадим еще одну функцию под названием createMovie (). Он будет использоваться для добавления нового фильма.

const movies = [
        { title: `A New Hope`, body:`After Princess Leia, the leader of the Rebel Alliance, is held hostage by Darth Vader, Luke and Han Solo must free her and destroy the powerful weapon created by the Galactic Empire.`},
        { title: `The Empire Strikes Back`, body: `Darth Vader is adamant about turning Luke Skywalker to the dark side. Master Yoda trains Luke to become a Jedi Knight while his friends try to fend off the Imperial fleet.` }
    ]

function getMovies(){
    setTimeout(() => {
        movies.forEach((movie, index) => {
            console.log(movie.title)
        })
    }, 1000);
}

function createMovies(movie){
    setTimeout(() => {
        movies.push(movie)
    }, 2000);
}

getMovies();


createMovies({ title: `Return of the Jedi`, body:`Luke Skywalker attempts to bring his father back to the light side of the Force. At the same time, the rebels hatch a plan to destroy the second Death Star.` });

Но проблема в том, что мы не получаем третий фильм на консоли. Это потому, что createMovie () занимает больше времени, чем getMovies (). Функция createMovie () заняла две секунды, а getMovies () — всего одну секунду.

Другими словами, getMovies () запускается перед createMovies (), и список фильмов уже отображается.

Чтобы решить эту проблему, мы можем использовать обратные вызовы Callback.

В createPost () передайте обратный вызов функции и вызовите функцию сразу после отправки нового фильма (вместо ожидания двух секунд).

const movies = [
        { title: `A New Hope`, body:`After Princess Leia, the leader of the Rebel Alliance, is held hostage by Darth Vader, Luke and Han Solo must free her and destroy the powerful weapon created by the Galactic Empire.`},
        { title: `The Empire Strikes Back`, body: `Darth Vader is adamant about turning Luke Skywalker to the dark side. Master Yoda trains Luke to become a Jedi Knight while his friends try to fend off the Imperial fleet.` }
    ]

function getMovies(){
    setTimeout(() => {
        movies.forEach((movie, index) => {
            console.log(movie.title)
        })
    }, 1000);
}

function createMovies(movie, callback){
    setTimeout(() => {
        movies.push(movie);
        callback();
    }, 2000);
}


createMovies({ title: `Return of the Jedi`, 
                body:`Luke Skywalker attempts to bring his father back to the light side of the Force. 
                At the same time, the rebels hatch a plan to destroy the second Death Star.` }, getMovies);

Теперь мы получаем обновленный список фильмов.

Как Promise работают в JavaScript?

Promise — это ценность, которая может принести пользу в будущем. Это значение может быть разрешено или не разрешено (в некоторых случаях ошибки, например, при сбое сети). Это работает как обещание из реальной жизни.

Он имеет три состояния: выполнено, отклонено или ожидает рассмотрения.

  • Выполнено: будет вызвана функция onFulfilled () (например, была вызвана функция resolve ()).
  • Отклонено: будет вызван onRejected () (например, был вызван reject ()).
  • На рассмотрении: еще не выполнено или отклонено.

Давайте посмотрим на пример:

const movies = [
        { title: `A New Hope`, body:`After Princess Leia, the leader of the Rebel Alliance, is held hostage by Darth Vader, Luke and Han Solo must free her and destroy the powerful weapon created by the Galactic Empire.`},
        { title: `The Empire Strikes Back`, body: `Darth Vader is adamant about turning Luke Skywalker to the dark side. Master Yoda trains Luke to become a Jedi Knight while his friends try to fend off the Imperial fleet.` }
    ]

function getMovies(){
    setTimeout(() => {
        movies.forEach((movie, index) => {
            console.log(movie.title)
        })
    }, 1000);
}

function createMovies(movie){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            movies.push(movie);

            const error = false;

            if(!error){
                resolve();
            }
            else{
                reject('Error: Something went wrong!')
            }
        }, 2000);
    })
}

createMovies({ title: `Return of the Jedi`, body:`Luke Skywalker attempts to bring his father back to the light side of the Force. At the same time, the rebels hatch a plan to destroy the second Death Star.`})
.then(getMovies);

Если мы получим ошибку, это будет что-то вроде «Ошибка: что-то пошло не так!», А если нет, обещание разрешится.

ак только обещание разрешено, оно вызывает ключевое слово .then () и getMovies ().

Наконец, как работает Async / Await в JavaScript

async означает асинхронный. Он позволяет программе запускать функцию без остановки всей программы. Это делается с помощью ключевого слова Async / Await.

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

async function example() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 2000)
  });

  let result = await promise; // wait until the promise resolves (*)

  alert(result); // "done!"
}

example();

Выполнение функции «приостанавливается» на строке (*) и возобновляется, когда обещание выполнено, и результатом становится результат. Таким образом, приведенный выше код показывает «готово!» за две секунды.

Давайте посмотрим на практический пример:

const movies = [
        { title: `A New Hope`, body:`After Princess Leia, the leader of the Rebel Alliance, is held hostage by Darth Vader, Luke and Han Solo must free her and destroy the powerful weapon created by the Galactic Empire.`},
        { title: `The Empire Strikes Back`, body: `Darth Vader is adamant about turning Luke Skywalker to the dark side. Master Yoda trains Luke to become a Jedi Knight while his friends try to fend off the Imperial fleet.` }
    ]

function getMovies(){
    setTimeout(() => {
        movies.forEach((movie, index) => {
            console.log(movie.title)
        })
    }, 1000);
}

function createMovies(movie){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            movies.push(movie);

            const error = false;

            if(!error){
                resolve();
            }
            else{
                reject('Error: Something went wrong!')
            }
        }, 2000);
    })
}

async function init(){
    await createMovies({ title: `Return of the Jedi`, body:`Luke Skywalker attempts to bring his father back to the light side of the Force. At the same time, the rebels hatch a plan to destroy the second Death Star.`});
    
    getMovies(); (*)
}

init();

В приведенном выше примере getMovies () в строке (*) ожидает выполнения createMovies () в функции async.

Другими словами, createMovies () является асинхронным, поэтому getMovies () будет запускаться только после завершения createMovies ().

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