前文
哈啰,宝子们,今天是笔者实习的第四周,领导让我开发一个很简单的根据在线不在的状态实时刷新显示的小功能,但是中途却遇到了很多坑,比如Vuex储存的数据无法持久化,需要联合查询,并发发起请求等。
写文章记录一下踩坑过程。(本文以伪代码形式展现,抱歉由于项目敏感,不能发源码上来)
一、需求描述
(1) 在一个可以根据唯一身份编号、使用设备类型、所属部门/单位去有条件的查询的人员通讯录上,新增功能,可默认展示人员数据时,将在线的人员排在最前面(通讯录做过分页处理,一页10-50条人员信息),并且新增字段,显示该人员是否在线(最后一次在线时间与服务器标准时间相差不到两分钟,判定为在线)
判断逻辑:在初次渲染时,后端接口会返回每个人员最后一次在线时间,我们只要对每个人的时间进行一次排序,时间最晚的,自然会留在最前面,并且拿到每个人的时间之后,与服务器标准时间(接口提供)做差就好
代码实现
console.log((new Date('服务器标准时间') - new Date('最后一次在线时间')) < 120000 ? '在线' : '不在线')
// 两分钟为120000毫秒
本来一行代码就可以实现的事情,但是由于后端接口忘记做数据的时间排序,而且由于某种原因,现在不可以修改后端的接口
那么,前端来做时间的排序是否可行呢?完全不可行。且不说后端的数据做过分页处理,一次最多获取50条数据。一页一页的排序根本没意义。就算后端返回全部的数据,前端一次拿到所有数据,进行排序,所耗费的性能,也是无法忍受的。
二、解决方案
直接调用别的在线人数接口(刚好有一个接口,可以根据发起请求的参数值0 ,1,2分别调用全部,在线,不在线的人员数量)
事情到这里就结束了吗?nonono。
原先老接口返回的数据中,刚好有一个需要渲染的字段,是新接口返回数据没有的
已经有点绕了吧,这个时候其实我们把新接口查询到的所有id编号(两个接口刚好都用同一个id属性判断人员信息)编成一个数组,在发起老接口请求携带这个数组,再将返回的特殊字段,和新数据拼接在一起,就完成了我们此次的目标。
事情真的结束了吗?当然没有!
老接口只支持单个id或者按页数查询,没有根据id数组查询的功能,这个时候,可以采取Promise.all()的方式发起并发请求(每次请求携带参数就是数组当中的一个id)
三、代码实现
// 定义函数 getTest
getTest() {
// 设置并发请求数组
const promiseArr = [];
// 调用 getCategoryData 函数并处理返回的 Promise
getCategoryData().then(res => {
const { data: { list } } = res;
// eslint-disable-next-line array-callback-return
// 正规流程是把id单独收集起来作为一个数组迭代,此处简写
// 遍历 list 数组
list.forEach((item) => {
// 创建一个新的 Promise 对象
const p = new Promise(function (resolve, reject) {
// 根据 item 的 category_id 计算 id
const id = item.category_id + 22;
// 调用 getProDetail 函数并处理返回的 Promise
getProDetail(id).then(res => {
resolve(res);
}).catch(e => {
reject(e);
});
});
// 将新的 Promise 对象添加到 promiseArr 数组中
promiseArr.push(p);
});
// 等待所有 Promise 对象都完成
Promise.all(promiseArr).then(rs => {
console.log(rs);
}).catch(e => {
console.log(e);
});
});
}
四、补充说明
(1)Promise.all()
Promise.all() 是 JavaScript 中的一个方法,它接收一个由 Promise 对象组成的数组作为参数,并返回一个新的 Promise 对象。这个新的 Promise 对象在数组中所有的 Promise 对象都已成功完成时才会变为 resolved 状态,如果数组中任何一个 Promise 对象被拒绝(rejected),那么新的 Promise 对象就会立即变为 rejected 状态,同时也会终止所有其他 Promise 对象的执行。
当 Promise.all() 返回的新的 Promise 对象被 resolved 时,它会携带一个数组参数,数组中的每个元素对应着传入 Promise.all() 的 Promise 对象数组中的每个 Promise 对象的成功值(resolve 值)。这使得 Promise.all() 方法非常适合处理多个并行异步操作的情况,只有当所有操作都成功完成时,才会执行接下来的逻辑。
(2)开发小技巧:
可以在请求最外部设置const self = this
避免变量污染
下一篇将讲解如何利用watch监听器搞定Vuex在项目中无法持久化存储的问题(挂载前、挂载后无法获取Vuex数据)