微信小程序中Promise.all处理异步请求的实践

9 次阅读

微信小程序开发过程中,经常需要同时请求多个接口,例如进入页面时同时获取用户信息、商品列表、轮播图数据、优惠券信息等。如果按照传统方式逐个调用接口,不仅代码结构复杂,还会增加页面加载等待时间。Promise.all作为JavaScript中处理多个异步任务的重要方法,可以有效提升异步请求管理能力,让微信小程序中的接口调用更加清晰、高效。

Promise.all的基本概念

Promise是一种用于处理异步操作的对象,它可以表示一个异步任务最终完成或失败后的结果。微信小程序中的网络请求wx.request本身并不是Promise形式,需要开发者进行封装,才能结合Promise语法使用。

Promise.all用于接收一个Promise数组,并等待所有Promise任务执行完成。

基本语法如下:

JavaScript
Promise.all([promise1, promise2, promise3])
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.log(error);
  });

当数组中的所有Promise都成功执行后,then方法会被调用,并返回一个结果数组。结果数组中的顺序与传入Promise的顺序保持一致,与实际完成时间无关。

如果其中任意一个Promise失败,Promise.all会立即进入catch流程。

微信小程序中封装wx.request为Promise

微信小程序默认提供的wx.request采用回调方式:

JavaScript
wx.request({
  url: 'https://example.com/api/data',
  success(res) {
    console.log(res.data);
  },
  fail(err) {
    console.log(err);
  }
});

当接口数量增加时,多层回调容易造成代码难以维护。因此,可以对wx.request进行Promise封装。

示例:

JavaScript
function request(options) {
  return new Promise((resolve, reject) => {
    wx.request({
      ...options,
      success(res) {
        resolve(res.data);
      },
      fail(error) {
        reject(error);
      }
    });
  });
}

封装完成后,就可以使用Promise链式调用:

JavaScript
request({
  url: '/api/user'
}).then(data => {
  console.log(data);
});

这种方式为后续使用Promise.all处理多个请求提供了基础。

Promise.all并发请求多个接口

假设小程序首页需要加载三个数据:

  • 用户基本信息

  • 商品列表

  • 活动推荐数据

可以使用Promise.all同时发起请求。

示例代码:

JavaScript
Page({
  data: {
    userInfo: {},
    products: [],
    activity: []
  },

  onLoad() {
    Promise.all([
      request({
        url: '/api/user'
      }),
      request({
        url: '/api/products'
      }),
      request({
        url: '/api/activity'
      })
    ])
    .then(([user, products, activity]) => {
      this.setData({
        userInfo: user,
        products: products,
        activity: activity
      });
    })
    .catch(error => {
      console.log('请求失败', error);
    });
  }
});

相比依次请求:

JavaScript
request('/api/user')
  .then(() => {
    return request('/api/products');
  })
  .then(() => {
    return request('/api/activity');
  });

Promise.all可以让多个请求同时执行,减少整体等待时间。

Promise.all执行机制分析

Promise.all具有以下几个特点:

1. 并发执行

Promise.all不会等待第一个请求完成后再执行第二个请求,而是同时启动所有Promise任务。

例如:

JavaScript
const task1 = request('/api/a');
const task2 = request('/api/b');

Promise.all([task1, task2]);

两个接口会同时发送网络请求。

2. 返回结果顺序固定

假设:

JavaScript
Promise.all([
  request('/api/a'),
  request('/api/b'),
  request('/api/c')
])
.then(result => {
  console.log(result);
});

即使接口c最快返回,最终结果仍然是:

JavaScript
[
  a的数据,
  b的数据,
  c的数据
]

这对于页面数据组合非常方便。

3. 任意失败导致整体失败

例如三个接口:

JavaScript
Promise.all([
  getUser(),
  getGoods(),
  getBanner()
])

如果getGoods请求失败:

JavaScript
reject('商品接口错误')

整个Promise.all会进入catch。

因此,对于非关键接口,需要根据业务场景决定是否使用Promise.all。

微信小程序页面初始化中的实际应用

很多小程序页面进入时,需要等待多个基础数据加载完成后再展示。

例如订单详情页:

  • 获取订单信息

  • 获取物流状态

  • 获取推荐商品

代码如下:

JavaScript
async loadPageData() {
  try {
    const [
      order,
      logistics,
      recommend
    ] = await Promise.all([
      request({
        url: '/order/detail'
      }),
      request({
        url: '/order/logistics'
      }),
      request({
        url: '/goods/recommend'
      })
    ]);

    this.setData({
      order,
      logistics,
      recommend
    });

  } catch(error) {
    console.error(error);
  }
}

结合async和await后,代码逻辑更加接近同步写法,可读性更强。

Promise.all与Promise.allSettled的区别

实际开发中,有些请求失败并不影响页面展示。

例如首页:

  • 广告接口失败,不影响商品展示

  • 推荐接口失败,不影响用户信息显示

这种情况下,Promise.all并不是最佳选择。

Promise.all:

JavaScript
Promise.all([
  request1,
  request2,
  request3
])

特点:

  • 一个失败,全部失败

  • 适合所有数据必须完整返回的场景

Promise.allSettled:

JavaScript
Promise.allSettled([
  request1,
  request2,
  request3
])
.then(result => {
  console.log(result);
});

特点:

  • 等待所有请求结束

  • 无论成功失败都会返回结果

  • 适合多个独立模块加载

例如:

JavaScript
[
  {
    status: "fulfilled",
    value: 数据
  },
  {
    status: "rejected",
    reason: 错误原因
  }
]

开发者可以根据status分别处理。

Promise.all使用中的常见问题

请求数量过多导致压力增加

虽然Promise.all可以提升速度,但同时发送大量请求可能造成:

  • 服务器压力增加

  • 网络资源竞争

  • 小程序加载体验下降

例如:

JavaScript
Promise.all([
  api1(),
  api2(),
  api3(),
  api4(),
  api5()
]);

如果接口数量非常多,可以考虑:

  • 合并接口

  • 分批请求

  • 增加缓存机制

忽略错误处理

部分开发者直接:

JavaScript
Promise.all(tasks)
.then(data => {
});

没有catch处理。

网络异常时可能导致页面出现空白状态。

建议:

JavaScript
Promise.all(tasks)
.then(data => {
})
.catch(error => {
  wx.showToast({
    title:'数据加载失败',
    icon:'none'
  });
});

页面销毁后继续更新数据

如果请求时间较长,而用户已经离开页面:

JavaScript
this.setData({
  list:data
});

可能产生无效更新。

实际项目中可以结合页面生命周期判断:

JavaScript
if(this.route){
  this.setData({
    list:data
  });
}

Promise.all在小程序项目中的优化技巧

使用统一请求管理

大型项目建议建立request.js:

JavaScript
export function request(url, data) {
  return new Promise((resolve,reject)=>{
    wx.request({
      url,
      data,
      success:res=>{
        resolve(res.data);
      },
      fail:reject
    });
  });
}

所有接口统一管理,方便后期维护。

配合loading提升体验

多个接口加载时:

JavaScript
wx.showLoading({
  title:'加载中'
});

Promise.all(tasks)
.then(result=>{
  
})
.finally(()=>{
  wx.hideLoading();
});

用户可以明确知道页面正在加载。

合理选择Promise方案

实际开发中:

  • 数据全部依赖 → Promise.all

  • 数据互不影响 → Promise.allSettled

  • 前后有依赖关系 → Promise链式调用

  • 单个异步任务 → 普通Promise即可

总结

Promise.all是微信小程序处理多接口异步请求的重要工具,通过将wx.request进行Promise化封装,可以实现多个接口并发执行,提高页面加载效率,同时让代码结构更加简洁。

在实际项目开发中,需要根据业务需求合理选择Promise.all或其他异步方案。对于必须同时成功的数据,可以使用Promise.all统一处理;对于互相独立的数据,则可以结合Promise.allSettled提升容错能力。掌握Promise异步管理方式,可以有效提升微信小程序开发效率和项目维护质量。