«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Обещания в JavaScript: понимание, обработка и освоение асинхронного кода

Обещания в JavaScript: понимание, обработка и освоение асинхронного кода

Опубликовано 7 ноября 2024 г.
Просматривать:153

Promises in JavaScript: Understanding, Handling, and Mastering Async Code

Введение

Раньше я работал Java-разработчиком и помню, как впервые столкнулся с обещаниями в JavaScript. Несмотря на то, что концепция казалась простой, я все еще не мог до конца понять, как работают обещания. Ситуация изменилась, когда я начал использовать их в проектах и ​​понял, какие кейсы они решают. Затем наступил момент АГА, и все стало более ясно. Со временем «Обещания» стали ценным оружием в моем арсенале. Как ни странно, приятно, когда я могу использовать их в работе и решать асинхронную обработку между функциями.

Возможно, вы впервые столкнулись с обещаниями при получении данных из API, что также является наиболее распространенным примером. Недавно я давал интервью, и угадайте, какой был первый вопрос: «Можете ли вы сказать мне разницу между Promise и Async Await?». Я приветствую это, поскольку считаю это хорошей отправной точкой для лучшего понимания того, как заявитель понимает, как работают механизмы. Однако он или она в основном использует другие библиотеки и фреймворки. Это позволило мне записать различия и описать передовые методы обработки ошибок асинхронных функций.

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

Давайте начнем с первоначального вопроса: «Какое обещание?» Обещание — это заполнитель для значения, которое мы еще не знаем, но мы получим его в результате асинхронного вычисления/функции. Если обещание сбудется, то мы получим результат. Если обещание не выполняется, оно вернет ошибку.

Базовый пример обещания

Определение обещания

Вы определяете Promise, вызывая его конструктор и передавая две функции обратного вызова: resolve и reject.

const newPromise = new Promise((resolve, reject) => {
    resolve('Hello');
    // reject('Error');
});

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

Получение результата обещания

Затем мы используем встроенную функцию, чтобы получить результат обещания. Он имеет два переданных обратных вызова: результат и ошибку. Результат вызывается, когда обещание успешно разрешено функциейsolve. Если обещание не разрешено, вызывается вторая функция error. Эта функция запускается либо при отклонении, либо при возникновении другой ошибки.

newPromise.then(result => {
    console.log(result); // Hello
}, error => {
    console.log("There shouldn't be an error");
});

В нашем примере мы получим результат Hello, потому что мы успешно выполнили обещание.

Обработка ошибок обещаний

Когда обещание отклоняется, всегда вызывается второй обратный вызов при ошибке.

const newPromise1 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise1');
});

newPromise1.then(
  (result) => {
    console.log(result); // It is not invoked
  },
  (error) => {
    console.log(error); // 'An error occurred in Promise1'
  }
);

Для большей ясности более рекомендуемый подход — использовать встроенный метод catch.

const newPromise2 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise2');
});

newPromise2
  .then((result) => {
    console.log(result); // It is not invoked
  })
  .catch((error) => {
    console.log(error); // 'An error occurred in Promise2'
  });

catch метод связан и имеет собственный обратный вызов ошибки. Он вызывается, когда обещание отклонено.

Обе версии работают хорошо, но цепочка, по моему мнению, более читабельна и удобна при использовании других встроенных методов, которые мы рассмотрим далее.

Объединение обещаний

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

getJSON('categories.json')
    .then(categories => {
        console.log('Fetched categories:', categories);

        return getJSON(categories[0].itemsUrl);
    })
    .then(items => {
        console.log('Fetched items:', items);

        return getJSON(items[0].detailsUrl);
    })
    .then(details => {
        console.log('Fetched details:', details);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

В нашем примере это служит для сужения результатов поиска для получения подробных данных. Каждая функция then также может иметь обратный вызов ошибки. Если нас заботит только обнаружение ошибок в цепочке вызовов, мы можем использовать функцию catch. Он будет оценен, если какой-либо из промисов вернет ошибку.

Обещай всем

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

Promise.all([
    getJSON('categories.json'),
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(results => {
        const categories = results[0];
        const techItems = results[1];
        const scienceItems = results[2];

        console.log('Fetched categories:', categories);
        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);

        // Fetch details of the first item in each category
        return Promise.all([
            getJSON(techItems[0].detailsUrl),
            getJSON(scienceItems[0].detailsUrl)
        ]);
    })
    .then(detailsResults => {
        const laptopDetails = detailsResults[0];
        const physicsDetails = detailsResults[1];

        console.log('Fetched laptop details:', laptopDetails);
        console.log('Fetched physics details:', physicsDetails);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

Promise.all принимает массив промисов и возвращает массив результатов. Если один из промисов отклонен, то и Promise.all также отклоняется.

Гоночные обещания

Еще одна встроенная функция — Promise.race. Он используется, когда у вас есть несколько асинхронных функций — промисов — и вы хотите их протестировать.

Promise.race([
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(result => {
        console.log('First resolved data:', result);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

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

Что такое асинхронное ожидание

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

Базовый пример Async Await

const fetchData = async () => {
    try {
        // Fetch the categories
        const categories = await getJSON('categories.json');
        console.log('Fetched categories:', categories);

        // Fetch items from the first category (Technology)
        const techItems = await getJSON(categories[0].itemsUrl);
        console.log('Fetched technology items:', techItems);

        // Fetch details of the first item in Technology (Laptops)
        const laptopDetails = await getJSON(techItems[0].detailsUrl);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error has occurred:', error.message);
    }
};

fetchData();

Наш fetchData помечен как асинхронный, и это позволяет нам использовать await для обработки асинхронных вызовов внутри функции. Мы вызываем больше промисов, и они будут оцениваться один за другим.

Мы используем блок try...catch, если хотим обработать ошибки. Отклоненная ошибка затем перехватывается в блоке catch, и мы можем действовать по ней, например, регистрируя ошибку.

Что отличается

Оба являются функциями обработки JavaScript с асинхронным кодом. Основное различие заключается в синтаксисе, когда промисы используют цепочку с then и catch, но синтаксис асинхронного ожидания более синхронен. Это облегчает чтение. Обработка ошибок для async await становится более простой, если используется блок try...catch. Это вопрос, который вы легко можете получить на собеседовании. Во время ответа вы можете углубиться в описание обоих и подчеркнуть эти различия.

Обещанные функции

Конечно, вы можете использовать все функции с асинхронным ожиданием. Например, Promise.all.

const fetchAllData = async () => {
    try {
        // Use await with Promise.all to fetch multiple JSON files in parallel
        const [techItems, scienceItems, laptopDetails] = await Promise.all([
            getJSON('technology_items.json'),
            getJSON('science_items.json'),
            getJSON('laptops_details.json')
        ]);

        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error occurred:', error.message);
    }
};

Практические примеры использования

Промисы — это фундаментальная функция JavaScript для обработки асинхронного кода. Вот основные способы его использования:

Получение данных из API

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

Обработка файловых операций

Асинхронное чтение и запись файлов можно выполнить с помощью промисов, особенно с помощью модуля Node.js fs.promises

import * as fs from 'fs/promises';

const writeFileAsync = async (filePath, content, options = {}) => {
    try {
        await fs.writeFile(filePath, content, options);
        console.log(`File successfully written to ${filePath}`);
    } catch (error) {
        console.error(`Error writing file to ${filePath}:`, error.message);
    }
};

const filePath = 'output.txt';
const fileContent = 'Hello, this is some content to write to the file!';
const fileOptions = { encoding: 'utf8', flag: 'w' }; // Optional file write options

writeFileAsync(filePath, fileContent, fileOptions);

Библиотеки на основе обещаний

Axios — это библиотека, с которой вам следует ознакомиться. Axios обрабатывает HTTP-запросы на клиенте и широко используется.

Express — это веб-фреймворк для Node.js. Он упрощает создание веб-приложений и API, а когда вы используете обещания с Express, ваш код остается чистым и простым в управлении.

Репозиторий с примерами

Все примеры можно найти по адресу: https://github.com/PrincAm/promise-example

Краткое содержание

Промисы — это фундаментальная часть JavaScript, необходимая для решения асинхронных задач в веб-разработке. Независимо от того, извлекаете ли вы данные, работаете с файлами или используете популярные библиотеки, такие как Axios и Express, вы часто будете использовать промисы в своем коде.

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

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

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

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/princam/promises-in-javascript-understanding-handling-and-mastering-async-code-10kn?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с [email protected] удалить его
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3