Skip to content

异步 Promise

shell
# Promise
ES6 引入的解决方案,代表一个异步操作的最终完成或失败
Promise 本身是个构造函数,接受一个回调函数作为参数,回调函数有两个参数,分别是 resolve reject ,二者都是方法,执行时传入最终成功或者失败的结果

# 优缺点
优点:链式调用解决了回调地狱问题,更好的错误处理(catch),更多的并发处理方法(Promise.all, Promise.race)
缺点:仍然需要回调(then/catch)

# 特点
状态一旦改变,不可逆
只能 pending fulfilled pending rejected

Promise 的所有方法

shell
# 实例方法
.then()
.catch()
.finally()


# 静态方法
Promise.resolve(value)                直接返回正确状态的 Promise 对象
Promise.reject(reason)                直接返回错误状态的 Promise 对象

Promise.all([p1,p2,p3])               "全成则成,一败则败" 入参为**可迭代的 Promise 列表**;全部成功则成功、任一失败则失败、返回与入参顺序一致的结果数组或第一个 rejection
Promise.allSettled([p1,p2,p3])        "等待所有,无论成败" 全部 settled 后返回状态数组(fulfilled/rejected 各自带 value/reason)
Promise.race([p1,p2,p3])              "竞速"**最先 settled** 的为准,成功则 fulfilled、失败则 rejected
Promise.any([p1,p2,p3])               "任一成功即成功" 任一 fulfilled 即成功;全部 rejected 才失败(ES2021,需运行环境支持)

使用案例

异步封装

  1. 在函数中返回 Promise 对象
  2. 在 Promise 构造函数的回调参数中执行异步操作
  3. 操作函数的 .then .catch 方法实现异步操作
js
function request() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const ok = Math.random() > 0.5;
      ok ? resolve('成功') : reject('失败');
    }, 500);
  });
}

request()
  .then((res) => console.log(res))
  .catch((err) => console.log(err));

并发 - 超时控制

js
function fetchWithTimeout(fetchPromise, timeout = 5000) {
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject('timeout'), timeout)
  })
  return Promise.race([fetchPromise, timeoutPromise])
}

并发 - 失败重试机制

js
async function retry(fn, maxTimes = 3) {
  try {
    return await fn()
  } catch (err) {
    if (maxTimes > 0) {
      return retry(fn, maxTimes - 1)
    }
    throw err
  }
}

并发 - 限制同时进行的最大请求数

同时最多执行 limit 个异步任务

js
async function concurrentLimit(tasks, limit = 2) {
  const result = []
  const executing = []

  for (const task of tasks) {
    const p = Promise.resolve(task()).then(res => result.push(res))
    executing.push(p)

    if (executing.length >= limit) {
      await Promise.race(executing)
    }
  }

  await Promise.all(executing)
  return result
}

接口并发请求(真实项目常用)

js
async function getData() {
  try {
    const [userList, orderList, goodsList] = await Promise.all([
      fetch('/api/userList').then(res => res.json()),
      fetch('/api/orderList').then(res => res.json()),
      fetch('/api/goodsList').then(res => res.json())
    ]);

    console.log('用户', userList);
    console.log('订单', orderList);
    console.log('商品', goodsList);
  } catch (err) {
    console.log('任意一个接口失败,整体失败', err);
  }
}

Promise.then() 方法的使用案例

js
// 红灯三秒、绿灯两秒、黄灯一秒,循环往复
function red() {
    console.log('red');
}
function green() {
    console.log('green');
}
function yellow() {
    console.log('yellow');
}

function light(timer,cb) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            cb()
            resolve()
        }, timer);
    })
}

function step() {
    Promise.resolve()
    .then(() => light(3000,red))
    .then(() => light(2000,green))
    .then(() => light(1000,yellow))
    .then(() => step())
}

// async await 方案
async function step() {
    await light(3000, red);    // 等3秒 → 亮红灯
    await light(2000, green);  // 等2秒 → 亮绿灯
    await light(1000, yellow); // 等1秒 → 亮黄灯
    step(); // 循环
}
    step()

JS 异步 Promise(另一稿)

解释一下 Promise 的原理和用法?

shell
# 用法
Promise 是一种异步操作的解决方案,用于处理异步操作的结果或错误。

# 原理
Promise 有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。状态一旦改变就不能再变。Promise 实例化时传入执行器函数,执行器函数立即执行,成功时调用 resolve,失败时调用 reject。

还可通过 Promise.all、Promise.race 等方法处理多个 Promise。