javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > js Promise使用

JavaScript中Promise讲解和使用方法代码

作者:新节

这篇文章主要介绍了JavaScript中Promise讲解和使用方法的相关资料,Promise是处理异步操作的优秀方案,可以使代码更加简洁、易读、易维护,避免回调地狱和嵌套过深的问题,需要的朋友可以参考下

PromiseJavaScript 异步编程的核心解决方案,它解决了传统回调地狱问题,提供了更优雅的异步控制流。

面试官:谈谈你对 Promise 的理解?

回答:

Promise 用来解决异步回调问题,由于 js
是单线程的,很多异步操作都是依靠回调方法实现的,这种做法在逻辑比较复杂的回调嵌套中会相当复杂;也叫做回调地狱;

promise 用来将这种繁杂的做法简化,让程序更具备可读性,可维护性;promise
内部有三种状态,pending,fulfilled,rejected

pending 表示程序正在执行但未得到结果,即异步操作没有执行完毕,

fulfilled 表示程序执行完毕,且执行成功,

rejected 表示执行完毕但失败;这里的成功和失败都是逻辑意义上的;并非是要报错。

其实,promise 和回调函数一样,都是要解决数据的传递和消息发送问题,promise 中的 then
一般对应成功后的数据处理,catch 一般对应失败后的数据处理。

一、Promise 基础概念

1.1 什么是 Promise?

Promise 是一个表示异步操作最终完成或失败的对象,它有三种状态:

1.2 创建 Promise

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve("操作成功");
    } else {
      reject("操作失败");
    }
  }, 1000);
});

1.3 使用 Promise

promise
  .then((result) => {
    console.log(result); // "操作成功"
  })
  .catch((error) => {
    console.error(error); // "操作失败"
  });

二、Promise 自带方法

2.1 静态方法

Promise.resolve()

创建一个立即解析的 Promise:

Promise.resolve("立即返回").then(console.log); // "立即返回"

Promise.reject()

创建一个立即拒绝的 Promise:

Promise.reject("错误").catch(console.error); // "错误"

Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。等待所有 Promise 完成,或任意一个失败。

“致命伤”:一个失败,全盘皆输

// 假设有三个异步请求:获取用户信息、获取商品列表、获取消息通知
const fetchUserInfo = fetch("/api/user");
const fetchProducts = fetch("/api/products");
const fetchNotifications = fetch("/api/notifications");

Promise.all([fetchUserInfo, fetchProducts, fetchNotifications])
  .then(([userInfo, products, notifications]) => {
    // 只有当三个请求都成功时,才会进入这里
    renderUserPage(userInfo, products, notifications);
  })
  .catch((error) => {
    // 如果任何一个请求失败,就会跳到这里
    console.error("有一个请求失败了:", error);
    showErrorPage("页面加载失败,请重试!");
  });

Promise.race()

返回最先完成的 Promise(无论成功或失败):

const p1 = new Promise((res) => setTimeout(res, 100, "慢"));
const p2 = new Promise((res) => setTimeout(res, 50, "快"));

Promise.race([p1, p2]).then((winner) => {
  console.log(winner); // "快"
});

Promise.allSettled()

为了解决 Promise.all 一个失败,全盘皆输的这个痛点,ES2020 引入了 Promise.allSettled 方法。它的行为更加宽容和稳健:

每个结果对象都有两种形态:

如何使用 Promise.allSettled:

Promise.allSettled([fetchUserInfo, fetchProducts, fetchNotifications]).then((results) => {
  // 注意:这里永远不会 catch
  // results 是一个包含三个对象的数组
  const userInfo = results[0].status === "fulfilled" ? results[0].value : null;
  const products = results[1].status === "fulfilled" ? results[1].value : null;
  const notifications = results[2].status === "fulfilled" ? results[2].value : null; // 我们可以针对每个结果进行精细化处理

  if (userInfo && products) {
    // 只要核心数据(用户和商品)还在,就渲染页面
    renderUserPage(userInfo, products, notifications); // notifications 可能是 null
    if (!notifications) {
      showToast("通知获取失败,不影响主要功能");
    }
  } else {
    // 如果核心数据缺失,再显示错误页
    showErrorPage("核心数据加载失败");
  }
});
// 不需要 .catch,因为它永远不会被触发

使用 Promise.allSettled 优势:

Promise.any()

返回第一个成功的 Promise(忽略失败):

const p1 = Promise.reject("错误1");
const p2 = Promise.resolve("成功");

Promise.any([p1, p2]).then((firstSuccess) => {
  console.log(firstSuccess); // "成功"
});

2.2 实例方法

.then()

处理 Promise 的成功状态:

fetch("/api")
  .then((response) => response.json())
  .then((data) => console.log(data));

.catch()

捕获 Promise 链中的错误:

fetch("/api")
  .then((response) => response.json())
  .catch((error) => console.error("请求失败:", error));

.finally()

无论成功或失败都会执行:

fetch("/api")
  .then((response) => response.json())
  .finally(() => console.log("请求结束"));

三、Promise 高级技巧

3.1 链式调用

function getUser(id) {
  return fetch(`/users/${id}`)
    .then((response) => response.json())
    .then((user) => fetch(`/profile/${user.profileId}`))
    .then((response) => response.json());
}

3.2 错误处理策略

// 方式1:每个 then 后单独 catch
fetch("/api")
  .then((res) => res.json())
  .catch(handleJSONError)
  .then((data) => process(data))
  .catch(handleProcessError);

// 方式2:全局 catch
fetch("/api")
  .then((res) => res.json())
  .then((data) => process(data))
  .catch(handleAnyError);

3.3 取消 Promise

原生 Promise 无法取消,但可以通过封装实现:

function cancellablePromise(promise) {
  let isCancelled = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then((value) => !isCancelled && resolve(value)).catch((error) => !isCancelled && reject(error));
  });

  return {
    promise: wrappedPromise,
    cancel: () => {
      isCancelled = true;
    }
  };
}

3.4 Promise 化回调函数

将回调风格的函数转换为 Promise:

const fs = require("fs");

function readFilePromise(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
}

四、Promise 与 async/await

4.1 基本转换

// Promise 风格
function getData() {
  return fetch("/api").then((res) => res.json());
}

// async/await 风格
async function getData() {
  const res = await fetch("/api");
  return res.json();
}

4.2 错误处理对比

// Promise
fetch("/api")
  .then((res) => res.json())
  .catch(console.error);

// async/await
try {
  const res = await fetch("/api");
  const data = await res.json();
} catch (err) {
  console.error(err);
}

五、常见问题与解决方案

5.1 Promise 内存泄漏

未处理的 Promise 拒绝会导致内存泄漏:

// 错误示范(未捕获的拒绝)
function riskyOperation() {
  return new Promise((_, reject) => {
    setTimeout(reject, 1000, "错误");
  });
}

// 正确做法
riskyOperation().catch(() => {});

5.2 并行与顺序执行

// 顺序执行
async function sequential() {
  await task1();
  await task2(); // 等待 task1 完成
}

// 并行执行
async function parallel() {
  await Promise.all([task1(), task2()]);
}

六、总结

Promise 的核心优势:

  1. 链式调用:解决回调地狱
  2. 统一错误处理:通过 .catch() 集中管理
  3. 组合能力强Promise.all/race 等实现复杂控制流

最佳实践建议:

// 终极实践示例
async function getFullData() {
  try {
    const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
    return { user, posts };
  } catch (error) {
    console.error("加载失败:", error);
    throw error; // 向上传递
  }
}

常用方法的区别

方法核心逻辑成功条件失败条件典型使用场景
Promise.all(iterable)“全部成功”
等待所有 Promise 完成
所有 Promise 都成功 (fulfilled)任意一个 Promise 失败 (rejected)并行处理多个相互依赖的任务,如:同时上传多张图片、同时获取多个 API 数据以渲染页面。
Promise.race(iterable)“竞赛”
取最先完成(无论成败)的 Promise 结果
最先完成的 Promise 是成功 (fulfilled)最先完成的 Promise 是失败 (rejected)1. 设置超时/竞速:为异步操作添加超时限制。
2. 从多个最快响应的来源(如 CDN)获取资源。
Promise.allSettled(iterable)“无论成败”
等待所有 Promise 最终敲定 (settled)
总是成功
(返回每个 Promise 的最终状态和结果数组)
不会失败当需要知道每个异步操作的最终结果时,如:批量提交表单,无论单个成功或失败都需要记录日志或进行下一步处理。
Promise.any(iterable)“任一成功”
取最先成功的 Promise 结果
任意一个 Promise 成功 (fulfilled)所有 Promise 都失败 (rejected)1. 寻找最快可用资源:从多个镜像服务器下载同一个文件,使用最先响应的。
2. 提供备用方案,只要一个成功即可。

快速选择指南

当你面对多个异步操作时,可以这样选择:

总结

到此这篇关于JavaScript中Promise讲解和使用方法的文章就介绍到这了,更多相关js Promise使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文