Введение в Promises, Async / Await в JavaScript

Знакомо ли вам чувство, когда вы так и не поняли очень важную тему так, как следовало бы? Ну, это я с «Обещаниями». В этом смысле я решил написать эту статью, чтобы мы могли спокойно разобраться, в чем суть этих обещаний.

Так что давайте перейдем к делу!

Что такое обещания?

Promise — чрезвычайно полезный и широко используемый инструмент в JavaScript, поскольку он позволяет выполнять последовательность команд асинхронно. Другими словами, он позволяет выполнять две части вашего кода одновременно.

В этом смысле вы получите ряд преимуществ, таких как более эффективное управление кодом, манипулирование данными в вызовах API и более чистая обработка ошибок.

Рассмотрим пример синхронной (традиционной) последовательности команд функции, которая складывает два числа и возвращает другую функцию с ответом:

function sumNumbers() {
    let result = 1 + 1;

    if (result == 2) {
        successCallback();
    } else {
        errorCallback();
    }
}

function successCallback() {
    console.log("Funcionou. A soma de 1 + 1 é 2")
}

function errorCallback() {
    console.log("Oops! Algo deu errado.");
}

sumNumbers();

// output: Funcionou. A soma de 1 + 1 é 2
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь давайте переделаем предыдущий код так, чтобы на этот раз он возвращал Promise. Это обещание упростит использование обратных вызовов, проверьте его.

Для этого мы создаем new Promise, который представляет собой класс, возвращающий объект. При создании этого класса мы передадим анонимную функцию в качестве параметра, которая в свою очередь получит параметры resolve и reject.

Запутались? Расслабьтесь, в примере это станет понятнее, а пока обратите внимание на параметры resolve и reject. Что означают эти параметры? Они означают, что если код работает так, как должен, он выполнит часть кода resolve. Если возникнут ошибки, будет выполнен чанк reject.

Эти resolve и reject являются тем, что мы называем обратными вызовами.

let p = new Promise((resolve, reject) => {
    let a = 1 + 1;
    if (a == 2) {
        resolve('Success');
    } else {
        reject('Failed');
    }
});
Войдите в полноэкранный режим Выход из полноэкранного режима

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

p.then((message) => {
    console.log('Esse é o then: ' + message);
}).catch((err) => {
    console.log('Esse é o catch: ' + err);
});

// output: Esse é o then: Success

// Caso mudássemos a condicional a == 2 para qualquer outro valor, provavelmente o output seria o do catch:
// output: Esse é o catch: Failed
Войдите в полноэкранный режим Выход из полноэкранного режима

Создание обещаний

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

В данном случае у нас есть две синхронные функции обратного вызова, называемые errorCallback и callback. Они вернут объект со свойством name и message. Общая функция с вашим вызовом будет выглядеть примерно так:

const myName = 'Alan';

function whoAreYouCallback(callback, errorCallback) {
    if (myName != 'Alan') {
        errorCallback({
            name: 'Algo deu errado',
            message: myName + ' não é meu nome.'
        })
    } else {
        callback({
            name: myName,
            message: 'Olá, mundo!'
        });
    }
}

whoAreYouCallback((result) => {
    console.log(result.name + "? Sou eu! " + result.message);
}, (error) => {
    console.log(error.name + '. ' + error.message);
})

// output: Alan? Sou eu! Olá, mundo!
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь, чтобы вернуть обещание, вы увидите, что нам не нужно добавлять errorCallback и callback к параметрам функции, мы просто заставим эту функцию возвращать Promise напрямую.

Чтобы вернуть Promise, мы добавляем return new Promise(anonymous function) к обратным вызовам параметров анонимной функции.

Для вызова Promise мы добавляем .then для обработки сценария успеха и .catch для сценария неудачи:

const myName = 'Alan';

function whoAreYouCallback() {
    return new Promise((resolve, reject) => {
        if (myName != 'Alan') {
        reject({
            name: 'Algo deu errado',
            message: myName + ' não é meu nome.'
        })
    } else {
        resolve({
            name: myName,
            message: 'Olá, mundo!'
        });
    }
    })
}

whoAreYouCallback()
    .then((result) => {
        console.log(result.name + "? Sou eu! " + result.message);
    }).catch((error) => {
        console.log(error.name + '. ' + error.message);
    })

// output: Alan? Sou eu! Olá, mundo!
Войдите в полноэкранный режим Выход из полноэкранного режима

Суперспособность Promise: определение порядка вызова функций

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

В этом примере мы создадим два обещания и вызовем через традиционный метод .then/.catch:


// Criando a primeira promise

function bestF1DriverEver(driver) {
    return new Promise((resolve, reject) => {
        if (driver === 'Senna') {
            resolve ({
                success: true,
                driverName: 'Ayrton Senna',
                msg: driver + ' é o melhor piloto de F1 de todos os tempos!'
            });
        } else {
            reject ({
                success: false,
                msg: 'Esse não é o melhor piloto!'
            });
        }
    });
}

// Criando a segunda promise

function bestF1Car(response) {
    return new Promise((resolve, reject) => {
        if (response.success) {
            resolve('McLaren MP4/4 pilotada por ' + response.driverName);
        } else {
            reject('Resposta errada! Tente de novo')
        }
    });
}

// Chamando uma promise e depois a outra

bestF1DriverEver('Senna')
    .then(response => {
        console.log('Verificando resposta...');
        return bestF1Car(response);
    })
    .then(response => {
        console.log('Encontrando o melhor carro...');
        console.log(response);
    })
    .catch(err => {
        console.log(err.msg);
    })

// output: Verificando resposta...
// output: Encontrando o melhor carro...
// output: McLaren MP4/4 pilotada por Ayrton Senna
Войдите в полноэкранный режим Выход из полноэкранного режима

Если мы захотели создать больше последовательных вызовов обещаний для выполнения кода в определенном порядке только после окончания выполнения другой предыдущей функции, мы просто добавляем еще .then в вызов, возвращающий ранее использованное обещание, как это было в случае return bestF1Car(response).

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

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

Async / Await

Для решения проблемы сложности вложенности .then, async / await приходит, чтобы упростить работу по вызову обещаний.

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

С двумя обещаниями, созданными в предыдущем примере, мы можем вызвать их следующим образом:

async function runPromises() {

    const bestF1DriverResponse = await bestF1DriverEver('Senna');

    console.log(bestF1DriverResponse);

    const bestF1CarResponse = await bestF1Car(bestF1DriverResponse);

    console.log(bestF1CarResponse);
}

runPromises()

// output: {
//  "success": true,
//  "driverName": "Ayrton Senna",
//  "msg": "Senna é o melhor piloto de F1 de todos os tempos!"
//}

// output: McLaren MP4/4 pilotada por Ayrton Senna
Войдите в полноэкранный режим Выход из полноэкранного режима

Что если переданный параметр приведет к тому, что обещание попадет в ошибку .catch? В этом случае нам нужно обернуть наши вызовы внутри блока try / catch для обработки ошибки.

async function runPromises() {

    try {
        // chamando a promise com o parâmetro errado
        const bestF1DriverResponse = await bestF1DriverEver('Piquet');

        console.log(bestF1DriverResponse);

        const bestF1CarResponse = await bestF1Car(bestF1DriverResponse);

        console.log(bestF1CarResponse);
    } catch (err) {
        console.log(err.msg);
        // Como o parâmetro passado foi errado, ele cairá neste bloco catch
    }
}

runPromises()

// output: Esse não é o melhor piloto!
Войдите в полноэкранный режим Выход из полноэкранного режима

Использование async / await вместе с try / catch является большим преимуществом, так как try / catch будет ловить ошибки обещания в reject, а также может ловить и другие ошибки.

Краткое руководство

Что такое обещание?

Это объект, который «инкапсулирует» состояние выполнения (успех или неудача) и выполняет обратные вызовы на основе этого состояния.

Какая связь между Promise и callback?

Обратные вызовы — это параметры в функции обещания, которые отвечают за то, как будет вести себя обещание в зависимости от его результата. Два основных используемых обратных вызова: resolve и reject.

  • Resolve: Если обещание сработало, как ожидалось, этот обратный вызов вернет последовательность разрешения кода.

  • Reject: Если обещание не сработало, как ожидалось, этот обратный вызов вернет ошибку для вызова обещания.

Какая связь между Promise и Async / Await?

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

Что Async / Await делает с нашим кодом?

Он будет выполнять блок .then без необходимости вложения их для каждого вызова promise, что делает код более читабельным. Кроме того, для правильной обработки ошибок важно обернуть вызовы обещаний await вокруг блока try / catch.

Есть ли что-то еще, что нужно знать об обещаниях?

Да, недавно в Node.JS появилось обновление Promise.all для вызова нескольких обещаний в еще меньшем количестве строк кода.

О, и никогда не забывайте, что вы всегда можете положиться на MDN Docs, чтобы получить информацию из надежного источника!


Заключение

Я считаю, что мы рассмотрели основные темы о Promises и Async/Await отсюда. Теперь это просто практика!

Спасибо моему техническому руководителю Эдгарду Леалу, который всегда поддерживает меня в учебе и побуждает быть лучшим специалистом.

Спасибо также ребятам из Source Code TV, которые своими видеороликами дали мне важную базу для содержания этой статьи.

Были какие-то проблемы? Комментируйте здесь ниже!

Если эта ссылка была для вас полезной или вы хотите поддержать мою работу,
оставьте свой лайк и поделитесь ❤️

Оцените статью
devanswers.ru
Добавить комментарий