最近接到个需求:清洗订单数据,数据量10W+。
实现逻辑很繁琐复杂:
循环拿到全部用户的邀请号ID —> 根据邀请号ID循环拿到所有对应的被邀请者ID —> 根据被邀请者ID拿到用户token —> 根据用户token查到全部订单 —> 循环检查全部订单状态(判断是否退费) —> 如果退费就取消对应邀请人的奖励红包 —> 扣除普通现金奖励红包后,重新计算邀请人数个数,生成阶梯红包。
业务代码确实很繁琐很复杂,其中最重要的还是邀请人与被邀请人是多对多关系,被邀请人拿订单详情是一对多关系,其中参杂各种判断和三重for循环,可想而知这个清洗数据接口放在服务器上面跑的话,影响是很大的。
因此,我这里拆分为线下接口调用线上接口缓解生产环境压力。具体步骤如下:
1:线下本地每次用get方式往生产的接口传入一个邀请人ID,也就是生产环境每次只清洗处理一个邀请人。
2:由于开发环境和生产环境数据库不同,因此把生产环境全部邀请人导出一个JSON文件。
3:线下本地开发环境读取JSON文件,每次传一个邀请人ID到生产接口清洗。
4:因为逻辑很长,要用延时器一个个发送,间隔为4秒。(测试接口3~5秒)
好了现在上代码,请无视业务代码,这里是自己一个记录学习而已:
先从生产库把真实生产环境的邀请人ID导出JSON。
放到随便一个地方,然后node读取该JSON文件。
坑点:
(1)读取文件一定要写绝对路径,相对路径找不到文件!
(2)fs方式读取出来的都是String类型,不信的话自己加个Type of看一下data。不是看起来是JSON就是JSON类型了。
(3)在function 回调函数里面附值是没用的,除非强行变成同步。不信可以自己各个地方console.log()看一下。
// 先引入
const fs = require('fs');
fs.readFile(
// 注意这里一定要写绝对路径,相对路径无法识别。
'/Users/XXXX/Desktop/XXXXX_project/XXXXapi/app/controller/data.json',
'utf8',
async function(err, data) {
if (err) {
console.log(err);
}
// 一定要JSON转了才是JSON格式,不然读取都是String。
const dataList = JSON.parse(data);
},
);
因为node里面没有JAVA的sleep()线程睡眠,所以要自己实现让进程sleep()。times就是自己定义的传进来的多少秒。
function sleep(times) {
let now = new Date();
const exit = now.getTime() + times;
while (true) {
now = new Date();
if (now.getTime() > exit) {
return;
}
}
}
最后看完整代码:
坑点:
(1)setTimeout那种不适合用在for循环中的延时任务,一开始我也是死磕setTimeOut;但是仔细想:
A:如果for放在setTimeOut里面,那么就是延时N秒后一瞬间跑完for,达不到每个数据延时数秒再拿下一个数据。