DevGang
Авторизоваться

Понимание Promises в JavaScript

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

Что такое Promises в JavaScript?

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

Promises могут находиться в одном из трех состояний: ожидающие выполнения, выполненные или отклоненные. Начальное состояние promises, которое означает, что асинхронная операция все еще продолжается, находится в ожидании. Если операция выполняется успешно, promises переходит в состояние выполнено, а если возникает проблема, оно переключается в состояние отклонено. "Settling" описывает процесс перехода от ожидаемого к выполненному или отклоненному.

Этапы жизненного цикла Promise

Давайте подробно рассмотрим каждую фазу жизненного цикла промиса с примерами кода:

Ожидающий этап

Promise находится в состоянии ожидания, когда оно создано. В этот момент асинхронная операция все еще продолжается, и Promise не принимается и не отклоняется.

Вот пример:

const promise = new Promise((resolve, reject) => {
  // Asynchronous operation (e.g., fetching data from an API)
  // resolve(result) or reject(error) will be called later
});

Выполненный этап

Promise переходит в состояние выполнено после успешного завершения асинхронной операции. В этот момент становится доступным связанное значение (результат). Чтобы обработать выполненное Promise, мы используем метод .then().

Вот пример:

const promise = new Promise((resolve, reject) => {
  // Simulating an asynchronous operation
  setTimeout(() => {
    resolve("Operation succeeded!");
  }, 2000);
});

promise.then((result) => {
  console.log(result); // Output: "Operation succeeded!"
});

Отклоненный этап

В случае возникновения проблемы с асинхронной операцией Promise переходит в состояние отклонено. Это означает, что операция не удалась, и предоставляет объект ошибки с соответствующей информацией. Чтобы обработать отклоненный промис, мы используем метод .catch().

Вот пример:

const promise = new Promise((resolve, reject) => {
  // Simulating an asynchronous operation
  setTimeout(() => {
    reject(new Error("Something went wrong!"));
  }, 2000);
});

promise.catch((error) => {
  console.log(error.message); // Output: "Something went wrong!"
});

Цепочка Promises

Promises имеют ряд важных преимуществ, в том числе возможность объединять в цепочку несколько асинхронных операций, что улучшает читаемость кода и предотвращает ужасный «ад обратных вызовов». Мы достигаем этого, используя метод .then() для возврата нового Promise.

Вот пример:

const getUser = () => {
  return new Promise((resolve, reject) => {
    // Simulating an asynchronous operation
    setTimeout(() => {
      resolve({ id: 1, name: "John" });
    }, 2000);
  });
};

const getUserPosts = (user) => {
  return new Promise((resolve, reject) => {
    // Simulating an asynchronous operation
    setTimeout(() => {
      resolve(["Post 1", "Post 2"]);
    }, 2000);
 });
};

getUser()
  .then((user) => getUserPosts(user))
  .then((posts) => console.log(posts)); // Output: ["Post 1", "Post 2"]

Вспомогательные функции для Promises

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

Promise.all()

Когда все Promises во входном массиве выполнены, эта функция возвращает новое Promises, которое выполняется.

Вот пример:

const fetchUser = () => {
  return new Promise((resolve, reject) => {
    // Simulating an asynchronous API call to fetch user data
    setTimeout(() => {
      const user = { id: 1, name: "John" };
      resolve(user);
    }, 2000);
  });
};

const fetchPosts = () => {
  return new Promise((resolve, reject) => {
    // Simulating an asynchronous API call to fetch user posts
    setTimeout(() => {
      const posts = ["Post 1", "Post 2"];
      resolve(posts);
    }, 1500);
  });
};

const fetchComments = () => {
  return new Promise((resolve, reject) => {
    // Simulating an asynchronous API call to fetch user comments
    setTimeout(() => {
      const comments = ["Comment 1", "Comment 2"];
      resolve(comments);
    }, 1000);
  });
};

Promise.all([fetchUser(), fetchPosts(), fetchComments()])
  .then(([user, posts, comments]) => {
    console.log("User:", user);
    console.log("Posts:", posts);
    console.log("Comments:", comments);
  })
  .catch((error) => {
    console.log("Error:", error);
  });

Три функции fetchUser(), fetchPosts() и fetchComments() включены в приведенный выше пример. Для пользовательских данных, пользовательских сообщений и пользовательских комментариев каждая функция имитирует асинхронный вызов API, возвращая Promise.

Передавая массив Promises ([fetchUser(), fetchPosts(), fetchComments()]) в Promise.all(), мы создаем новый Promise, который выполняется после успешного завершения каждого Promise в массиве. При обработке выполнения метод .then() применяет синтаксис деструктуризации массива для получения разрешенных значений каждого Promise.

Когда в этой ситуации все Promise выполнены, деструктуризация массива присваивает разрешенные значения fetchUser(), fetchPosts() и fetchComments() переменным user, posts и comment соответственно. Пользователь, сообщения и комментарии затем записываются на консоль.

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

Promise.all() позволяет нам эффективно извлекать несколько асинхронных ресурсов и обрабатывать их все сразу после успешного завершения каждого запроса.

Promise.race()

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

Вот пример:

const fetchResource = (resource, delay) => {
  return new Promise((resolve, reject) => {
    // Simulating an asynchronous API call with a specified delay
    setTimeout(() => {
      resolve(`${resource} is fetched successfully in ${delay}ms`);
    }, delay);
  });
};

const resource1 = fetchResource("Resource 1", 2000);
const resource2 = fetchResource("Resource 2", 1500);
const resource3 = fetchResource("Resource 3", 1000);

Promise.race([resource1, resource2, resource3])
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.log(error);
  });

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

Когда массив Promise ([resource1, resource2, resource3]]) передается методу Promise.race(), создается новое Promise, которое выполняется (выполняется или отклоняется) в ответ на любое Promise в массиве. Разрешенное значение успешного промиса передается в качестве параметра result и записывается в консоль в методе .then(), который используется для обработки выполнения. В этом случае ресурс, который разрешится первым (т. е. с наименьшей задержкой), будет считаться победителем, и его разрешенное значение будет выведено на консоль.

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

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

Promise.resolve() и Promise.reject()

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

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

Promise.resolve() и Promise.reject() используются в следующем примере кода:

const fetchData = (shouldSucceed) => {
  if (shouldSucceed) {
    return Promise.resolve("Data fetched successfully");
  } else {
    return Promise.reject(new Error("Failed to fetch data"));
  }
};

fetchData(true)
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.log(error);
  });

fetchData(false)
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.log(error);
  });

Функция fetchData() в приведенном выше примере имеет параметр shouldSucceed, который указывает, должна ли выборка данных быть успешной или неудачной. Promise.resolve() используется для создания и возврата промиса, который немедленно выполняется с сообщением "Data fetched successfully", если shouldSucceed имеет значение true. Promise.reject() используется для создания и возврата промиса, который немедленно отклоняется с новым объектом Error и сообщением «Не удалось получить данные», если shouldSucceed имеет значение false.

Возвращенное промис выполняется при первом вызове fetchData() с параметром shouldSucceed, установленным в true, а выполнение управляется методом .then(). Параметру result передается разрешенное значение "Data fetched successfully", которое затем регистрируется в консоли.

При втором вызове fetchData() с параметром shouldSucceed, установленным в false, возвращенное Promise отклоняется, и для обработки отклонения используется метод .catch(). Объект ошибки, содержащий сообщение "Failed to fetch data", передается в качестве параметра error и заносится в консоль.

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

Вывод

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

В этом обширном руководстве были рассмотрены определение промисов, этапы их жизненного цикла и функции вспомогательных функций, таких как Promise.all(), Promise.race(), Promise.resolve() и Promise.reject(). Мы можем эффективно обрабатывать асинхронные операции и изящно обрабатывать сценарии успеха и ошибки, понимая этапы жизненного цикла — pending, fulfilled и rejected.

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

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

Источник:

#JavaScript #Начинающим
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу