Promise 的场景和最佳实践

Promise 是 JavaScript 中用于处理异步操作的一个对象,它表示一个异步操作的最终结果,可能是成功或失败,Promise 通常用于处理异步操作,比如从服务器获取数据读取文件定时任务用户操作

基本的使用

js 复制代码
const myPromise = new Promise((resolve, reject) => {
  const success = true;
  
  if(success) {
    resolve("操作成功!");
  } else {
    reject("操作失败。");
  }
});

myPromise
  .then(result => console.log(result))  // 如果 Promise 成功
  .catch(error => console.log(error));  // 如果 Promise 失败

常见的用法和示例

  1. 链式调用 (then)

Promise 支持链式调用,可以在一个 then 后接着另一个 then,处理不同的异步操作。

js 复制代码
new Promise((resolve, reject) => {
  setTimeout(() => resolve("第一个操作成功!"), 1000);
})
.then(result => {
  console.log(result);  // 输出: 第一个操作成功!
  return "第二个操作成功!";
})
.then(result => {
  console.log(result);  // 输出: 第二个操作成功!
});
  1. 多个 Promise 的并行执行 (Promise.all)

如果你有多个独立的异步操作,并且你希望它们并行执行,可以使用 Promise.all,它会等到所有的 Promise 都完成后再继续执行。

js 复制代码
const promise1 = new Promise(resolve => setTimeout(() => resolve("操作1完成"), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve("操作2完成"), 2000));

Promise.all([promise1, promise2])
  .then(results => {
    console.log(results);  // 输出: ["操作1完成", "操作2完成"]
  });
  1. 处理单个 Promise 的异常 (catch)

catch 方法是用来捕捉 Promise 中的异常的,它可以让你在异步操作失败时处理错误。

js 复制代码
new Promise((resolve, reject) => {
  setTimeout(() => reject("操作失败!"), 1000);
})
.then(result => {
  console.log(result);
})
.catch(error => {
  console.log("捕获错误:", error);  // 输出: 捕获错误: 操作失败!
});
  1. Promise 的竞态条件 (Promise.race) Promise.race 会返回第一个完成的 Promise,不管它是成功还是失败。
js 复制代码
const promise1 = new Promise(resolve => setTimeout(() => resolve("操作1完成"), 2000));
const promise2 = new Promise(resolve => setTimeout(() => resolve("操作2完成"), 1000));

Promise.race([promise1, promise2])
  .then(result => {
    console.log(result);  // 输出: 操作2完成
  });
  1. 串联多个异步操作 (async/await)

async/awaitPromise 的语法糖,使得异步操作看起来像是同步的。

js 复制代码
async function run() {
  try {
    const result1 = await new Promise(resolve => setTimeout(() => resolve("操作1完成"), 1000));
    console.log(result1);
    const result2 = await new Promise(resolve => setTimeout(() => resolve("操作2完成"), 1000));
    console.log(result2);
  } catch (error) {
    console.log("捕获错误:", error);
  }
}

run();

async 函数中,你可以使用 await 等待 Promise 的结果,这使得异步代码更简洁易读。

在实际项目中使用

  1. API 请求

在开发前端应用时,向后端请求数据是最常见的异步操作。通常会使用 Promise 来处理 API 请求, 通常会使用 async/await 来简化这类代码。

js 复制代码
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    console.log("数据:", data);
  } catch (error) {
    console.error("获取数据失败:", error);
  }
}
  1. 多个异步操作并行执行 (Promise.all)

这种方式比一一等待每个请求更加高效,尤其是在多个请求之间没有依赖关系时

例如,加载多个 API 数据:

js 复制代码
const fetchData1 = fetch('https://api.example.com/data1').then(res => res.json());
const fetchData2 = fetch('https://api.example.com/data2').then(res => res.json());

Promise.all([fetchData1, fetchData2])
  .then(([data1, data2]) => {
    console.log("数据1:", data1);
    console.log("数据2:", data2);
  })
  .catch(error => {
    console.error("加载数据失败:", error);
  });
  1. 串联多个异步操作 (then)

一个异步操作完成后再执行下一个操作,这时可以使用 then 链式调用来处理。

例如,先提交表单数据,再获取结果:

js 复制代码
function submitForm(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 模拟异步表单提交
      if (data) resolve("表单提交成功");
      else reject("表单提交失败");
    }, 1000);
  });
}

submitForm({ name: 'John', age: 30 })
  .then(result => {
    console.log(result);  // 输出: 表单提交成功
    return fetch('https://api.example.com/result');  // 提交成功后获取结果
  })
  .then(response => response.json())
  .then(data => console.log("结果数据:", data))
  .catch(error => console.error("错误:", error));
  1. 处理复杂的异步控制流async/await

async/awaitPromise 的语法糖,使得异步代码看起来像同步代码,简化了逻辑结构,尤其是处理多层嵌套的异步调用时非常有用。

例如,用户登录后执行后续操作:

js 复制代码
async function loginUser(credentials) {
  try {
    const loginResponse = await fetch('https://api.example.com/login', {
      method: 'POST',
      body: JSON.stringify(credentials),
    });
    const loginData = await loginResponse.json();
    
    if (loginData.success) {
      const userProfile = await fetch('https://api.example.com/user/profile');
      const profileData = await userProfile.json();
      console.log("用户资料:", profileData);
    } else {
      console.error("登录失败");
    }
  } catch (error) {
    console.error("发生错误:", error);
  }
}
  1. 错误处理和重试机制

在项目中,经常会遇到某些操作可能会失败的情况,比如网络请求失败。你可以使用 catch 来捕获错误,甚至设置重试机制。

例如,添加重试机制:

js 复制代码
function fetchWithRetry(url, retries = 3) {
  return new Promise((resolve, reject) => {
    function attempt() {
      fetch(url)
        .then(response => {
          if (!response.ok) throw new Error("请求失败");
          return response.json();
        })
        .then(resolve)
        .catch(error => {
          if (retries > 0) {
            console.log(`重试剩余次数: ${retries}`);
            retries--;
            attempt();  // 重试
          } else {
            reject(error);  // 最终失败
          }
        });
    }
    attempt();
  });
}

fetchWithRetry('https://api.example.com/data')
  .then(data => console.log("数据:", data))
  .catch(error => console.error("最终错误:", error));
  1. 动画和延时操作 有时你需要在执行一系列操作时,插入一些动画或延时操作。你可以利用 Promise 来实现这一需求。

例如,延时执行:

js 复制代码
function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

delay(1000)  // 延迟1秒
  .then(() => console.log("1秒后执行"))
  .then(() => delay(2000))  // 再延迟2秒
  .then(() => console.log("再过2秒执行"));
相关推荐
Asort3 小时前
JavaScript 从零开始(四):基础语法详解——从变量声明到数据类型的完全指南
前端·javascript
木木jio3 小时前
前端大文件分片上传 —— 基于 React 的工程化实现
前端·javascript
南雨北斗3 小时前
JS的对象属性存储器
前端
Lotzinfly3 小时前
12个TypeScript奇淫技巧你需要掌握😏😏😏
前端·javascript·面试
一个大苹果3 小时前
setTimeout延迟超过2^31立即执行?揭秘JavaScript定时器的隐藏边界
javascript
开源之眼3 小时前
React中,useState和useReducer有什么区别
前端
普郎特3 小时前
"不再迷惑!用'血缘关系'彻底搞懂JavaScript原型链机制"
前端·javascript
可观测性用观测云3 小时前
前端错误可观测最佳实践
前端
恋猫de小郭3 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter