JS:Promise异步操作的最终结果(对象)

Promise 的基本概念

Promise 是一个表示异步操作最终结果的对象,可能的结果有 成功(resolved)失败(rejected)。Promise 主要用于处理异步操作的结果,并允许你在操作完成后进行相应的处理。

一个 Promise 对象有 三种状态

  1. Pending(等待中): 初始状态,表示异步操作还没有完成。
  2. Fulfilled(已完成): 异步操作成功完成,并返回结果。
  3. Rejected(已拒绝): 异步操作失败,并返回错误。

如何创建一个 Promise

// executor函数会在new的时候立即执行
const promise = new Promise((resolve, reject) => {
  // 执行异步操作
  const success = true; // 模拟操作成功或失败
  
  if (success) {
    resolve('成功的结果'); // 操作成功时,调用 resolve
  } else {
    reject('失败的原因'); // 操作失败时,调用 reject
  }
});

在构造函数 new Promise() 中,传入的参数是一个 executor 函数,接收两个参数:

  • resolve:当异步操作成功时调用。
  • reject:当异步操作失败时调用。

executor 函数在 new Promise 时立即同步执行

resolve(value)

  • 当异步操作成功时调用,它会将 Promise 的状态从 pending(等待中)转变为 fulfilled(已完成),并返回操作的成功结果。
  • value 是成功的结果,它会传递到后续链式调用的 then()
  • resolve 可以传递任何类型的值: 字符串、数字、对象、甚至另一个 Promise。

reject(reason)

  • 当异步操作失败时调用,它会将 Promise 的状态从 pending(等待中)转变为 rejected(已拒绝),并返回失败的原因或错误。
  • reason 是失败的原因或错误信息,它会传递到后续链式调用的 catch()then() 的第二个参数中。
  • reject 也可以传递任何类型的错误信息: 字符串、对象、错误对象等。
const promise = new Promise((resolve, reject) => {
  const success = true;
  
  if (success) {
    resolve({ message: "操作成功", code: 200 });  // 传递一个对象
  } else {
    reject(new Error("操作失败"));  // 传递一个 Error 对象
  }
});

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

then() 和**catch()**

then() 方法

then() 用于处理 Promise 成功 的结果。当 Promise 变为 fulfilled(成功) 状态时,then() 中的回调函数会被执行。

promise.then(onFulfilled, onRejected);
  • onFulfilled:Promise 成功时执行的回调函数,接收 Promise 的成功结果(resolve(value) 的值)。
  • onRejected:Promise 失败时执行的回调函数,接收 Promise 的失败原因(reject(reason) 的值)。

传参

  1. 如果你只传递一个回调函数给 then(),那么这个回调函数会默认处理 成功 的情况,也就是 onFulfilled,而 onRejected 会被忽略。

    const promise = new Promise((resolve, reject) => {
      resolve("操作成功");
    });
    
    promise
      .then(result => {
        console.log(result);  // 输出 "操作成功"
      });
    
    • 只传递了一个 then() 的回调,表示我们只处理成功的情况。
    • 如果 Promise 被拒绝(reject),则不会执行任何回调,也不会有错误处理。
  2. 如果同时传递两个回调函数

    const promise = new Promise((resolve, reject) => {
      const success = true;
      if (success) {
        resolve("操作成功");
      } else {
        reject("操作失败");
      }
    });
    
    promise
      .then(
        result => {
          console.log(result);  // 成功时输出 "操作成功"
        },
        error => {
          console.log(error);  // 失败时输出 "操作失败"
        }
      );
    
  3. 如果你只希望传递 失败 的回调函数(onRejected),可以这样做:

    const promise = new Promise((resolve, reject) => {
      reject("操作失败");
    });
    
    promise
      .then(null, error => {
        console.log(error);  // 输出 "操作失败"
      });
    
    • 这里我们只传递了失败的回调(onRejected),因此只有 Promise 失败时才会执行 error 回调并打印 "操作失败"
    • 如果 Promise 成功了,onFulfilled 会被忽略,什么也不会发生。

返回值

then() 中的回调函数不仅可以处理结果,还可以返回一个值,这个值将成为下一个 then() 的输入。

更重要的是,如果 then() 返回的是一个新的 Promisethen()等待这个 Promise 完成后再继续执行链式调用

返回普通值

new Promise((resolve, reject) => {
  resolve(1);
})
  .then(result => {
    return result + 1;  // 返回值 2
  })
  .then(result => {
    console.log(result);  // 输出 2
  })
  .catch(error => {
    console.error(error);
  });
  • 第一个 then() 返回 result + 1,即返回了 2,这个返回值会被传递到下一个 then() 中。
  • 第二个 then() 接收到返回值并打印。

返回 Promise

new Promise((resolve, reject) => {
  resolve(1);
})
  .then(result => {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(result + 1), 1000);
    });
  })
  .then(result => {
    console.log(result);  // 输出 2,等待内部的 Promise 完成
  })
  .catch(error => {
    console.error(error);
  });
  • 第一个 then() 返回了一个新的 Promise,这个 Promise 会在 1 秒后返回 result + 1
  • 第二个 then() 会等待上一个 Promise 完成后,接收到返回的 2 并打印。

catch()

catch() 用于处理 Promise 失败 的原因。它捕获在 then() 中抛出的异常或错误。

promise.catch(onRejected);
  • onRejected:当 Promise 被 rejected(失败) 时,执行的回调函数,接收失败的原因(reject(reason) 的值)。
  • catch() 本质上是 then(null, onRejected) 的语法糖。
new Promise((resolve, reject) => {
  resolve(1);
})
  .then(result => {
    return result + 1;  // 返回值 2
  })
  .then(result => {
    console.log(result);  // 输出 2
  })
  .catch(error => {
    console.error(error);
  });

catch() 方法不仅用于捕获 Promise 内部的错误,还可以捕获前面 then() 中的错误。

如果任何 then() 或异步操作抛出错误,catch() 会接收到错误并进行处理。

new Promise((resolve, reject) => {
  throw new Error("发生错误");
})
  .then(result => {
    console.log(result);  // 不会执行
  })
  .catch(error => {
    console.error(error.message);  // 输出 "发生错误"
  });
  • 在 Promise 中抛出错误,catch() 会捕获到这个错误并打印其 message

Promise 链式调用

Promise 支持链式调用,意味着每一个 .then() 返回一个新的 Promise 对象,因此可以继续进行链式调用。

const p = new Promise((resolve) => resolve(1));

p.then(res => res + 1)  // 返回 2
  .then(res => res * 2)  // 返回 4
  .then(res => console.log(res));  // 输出 4

Promise 的静态方法

Promise.resolve()

Promise.resolve() 返回一个 已完成(fulfilled)的 Promise 对象。

Promise.resolve(1).then(result => console.log(result));  // 输出 1

Promise.reject()

Promise.reject() 返回一个 已拒绝(rejected)的 Promise 对象。

Promise.reject("错误").catch(error => console.log(error));  // 输出 "错误"

Promise.all()

Promise.all() 用来并行执行多个异步操作,它会返回一个新的 Promise,只有当 所有 Promise 都成功 时才会触发 then,如果有任何一个 Promise 失败,就会触发 catch

Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
]).then(results => {
  console.log(results);  // 输出 [1, 2, 3]
}).catch(error => {
  console.error(error);
});

Promise.race()

Promise.race() 用于竞争多个异步操作,它会返回第一个完成的 Promise,无论它是成功还是失败。

Promise.race([
  new Promise(resolve => setTimeout(resolve, 1000, 'A')),
  new Promise(resolve => setTimeout(resolve, 500, 'B'))
]).then(result => {
  console.log(result);  // 输出 'B',因为它先完成
});

Promise.allSettled()

Promise.allSettled() 会等待所有 Promise 完成(不论成功或失败),并返回每个 Promise 的状态。

Promise.allSettled([
  Promise.resolve(1),
  Promise.reject('失败'),
  Promise.resolve(3)
]).then(results => {
  console.log(results);
  // 输出
  // [
  //   { status: 'fulfilled', value: 1 },
  //   { status: 'rejected', reason: '失败' },
  //   { status: 'fulfilled', value: 3 }
  // ]
});

Promise.any()

Promise.any() 会等待 第一个成功 的 Promise。如果所有 Promise 都失败,则返回一个错误。

Promise.any([
  Promise.reject('失败1'),
  Promise.resolve('成功'),
  Promise.reject('失败2')
]).then(result => {
  console.log(result);  // 输出 '成功'
}).catch(error => {
  console.log(error);
});

async/awaitPromise

async 函数

async 是一个关键字,用来声明一个异步函数。任何使用 async 声明的函数,都会隐式地返回一个 Promise 对象。

如果函数返回一个非 Promise 值,async 会自动将其包装成一个已经解决(fulfilled)的 Promise

async function fetchData() {
  return "数据加载完成";
}

fetchData().then(result => {
  console.log(result);  // 输出 "数据加载完成"
});
  • fetchData 是一个 async 函数,返回的 "数据加载完成" 会被自动包装成一个已解决(fulfilled)的 Promise,并在 .then() 中处理。

await 关键字

await 只能在 async 函数内使用。

await 会暂停函数的执行,直到 Promise 执行完毕并返回结果。

await 表达式返回的是 Promise 的解析值(resolve 的值)。如果 Promise 被拒绝(reject),await 会抛出一个错误。

async function fetchData() {
  const response = await new Promise(resolve => {
    setTimeout(() => resolve("数据加载完成"), 1000);  // 模拟异步操作
  });
  console.log(response);  // 输出 "数据加载完成"
}

fetchData();
  • await 会暂停执行,直到 Promise 返回 "数据加载完成",然后继续执行 console.log(response) 打印结果。

错误处理

async/await 中,我们使用 try/catch 来捕获异常,这与同步代码中的错误处理方式相同。

async function fetchData() {
  try {
    const response = await new Promise((resolve, reject) => {
      setTimeout(() => reject("发生错误"), 1000);  // 模拟异步失败
    });
    console.log(response);  // 不会执行
  } catch (error) {
    console.error("错误信息:", error);  // 输出 "错误信息: 发生错误"
  }
}

fetchData();
  • 由于 Promiserejectawait 会抛出一个错误,catch 会捕获到这个错误并打印出来。

结合 async/awaitPromise

// 模拟获取用户信息
function getUserInfo() {
  return new Promise(resolve => {
    setTimeout(() => resolve({ id: 1, name: "Tom" }), 1000);
  });
}

// 模拟根据用户ID获取订单信息
function getUserOrder(userId) {
  return new Promise(resolve => {
    setTimeout(() => resolve({ userId, orderId: 123 }), 1000);
  });
}

// 模拟根据订单ID获取订单详情
function getOrderDetails(orderId) {
  return new Promise(resolve => {
    setTimeout(() => resolve({ orderId, product: "Laptop", price: 1000 }), 1000);
  });
}

// 使用 async/await 执行异步操作
async function fetchOrderDetails() {
  try {
    const userInfo = await getUserInfo();
    console.log("用户信息:", userInfo);

    const orderInfo = await getUserOrder(userInfo.id);
    console.log("订单信息:", orderInfo);

    const orderDetails = await getOrderDetails(orderInfo.orderId);
    console.log("订单详情:", orderDetails);
  } catch (error) {
    console.error("发生错误:", error);
  }
}

fetchOrderDetails();
  • getUserInfogetUserOrdergetOrderDetails 都是返回 Promise 的函数。
  • fetchOrderDetails 中,我们使用 await 来等待这些异步操作依次完成。
  • 如果任何一个操作失败,catch 会捕获错误。

输出:

用户信息: { id: 1, name: 'Tom' }
订单信息: { userId: 1, orderId: 123 }
订单详情: { orderId: 123, product: 'Laptop', price: 1000 }

async/awaitPromise.all

async function fetchData() {
  try {
    const [user, order] = await Promise.all([
      getUserInfo(),  // 获取用户信息
      getUserOrder()   // 获取用户订单信息
    ]);
    console.log("用户信息:", user);
    console.log("订单信息:", order);
  } catch (error) {
    console.error("发生错误:", error);
  }
}

async function getUserInfo() {
  return new Promise(resolve => {
    setTimeout(() => resolve("用户信息加载完成"), 1000);
  });
}

async function getUserOrder() {
  return new Promise(resolve => {
    setTimeout(() => resolve("订单信息加载完成"), 1000);
  });
}

fetchData();
  • Promise.all 可以并行执行多个异步操作,这样可以提高效率,因为两个异步操作是并行执行的,而不是一个接一个地执行。
  • await 会等待 Promise.all 完成,结果是 [user, order],分别对应 getUserInfo()getUserOrder() 的结果。

async/await 的执行顺序

async 函数中的代码执行顺序与同步代码类似,但由于有 await,函数中的某些部分会暂停,直到 Promise 处理完成。

  1. 执行 async 函数。
  2. 遇到 await,会暂停执行并等待 Promise 完成。
  3. 一旦 Promise 完成,await 会返回 Promise 的结果,函数继续执行。
async function fetchData() {
  console.log("开始");

  const first = await new Promise(resolve => {
    setTimeout(() => resolve("第一步完成"), 1000);
  });
  console.log(first);

  const second = await new Promise(resolve => {
    setTimeout(() => resolve("第二步完成"), 1000);
  });
  console.log(second);

  console.log("结束");
}

fetchData();
  • await 会暂停函数执行,等待每一步 Promise 完成后,继续执行下一个操作。

  • 第一步完成第二步完成 是依次输出的,因为它们是顺序执行的。

  • 输出:

    开始
    第一步完成
    第二步完成
    结束
    

×

喜欢就点赞,疼爱就打赏