ms、s、min、h时间单位换算

一、背景

有一个延迟时间的字段数据,后端默认返回的是ms,但是返回的时候有可能数据量较大,所以需要前端根据后端返回的值去换算单位。

二、代码版本更迭

1. 第一版

思路: 根据后端返回的值和换算的临界值去判断。

缺点: 用了大量的if/else,代码不够简洁

export const timeConvert = function (timeValue) {
  if (isNaN(timeValue)) {
    return '';
  }
  const baseUnitLabel = ['ms', 's', 'min', 'h'];
  const basicValue = [1,1000,1000*60,1000*60*60]
  const exp1 = Math.floor(timeValue / 1000);
  let exp2;
  if (exp1 < 1) {
    exp2 = 0
  } else if (exp1 < 60) {
    exp2 =  1
  } else if(exp1 < 60 * 60)  {
    exp2 = 2
  } else {
    exp2 = 3
  }
  let resValue = timeValue/basicValue[exp2]
  if (resValue.toString().length > resValue.toFixed(2).toString().length) {
    resValue = resValue.toFixed(2);
  }
  return `${resValue} ${baseUnitLabel[exp2]}`;
};

2. 第二版

思路: 引入Math.log(value)/Math.log(60),利用指数和下标关联起来。

缺点: 临界单位的换算关系并不是都是1/60的关系,比如ms到s就是1/1000,需要分两种情况去分析考虑

优点: 省去了大量的if/else

相关代码如下:

export const timeConvert = function (timeValue) {
  if (isNaN(timeValue) || typeof timeValue != 'number') {
    return '';
  }
  const baseUnitLabel = ['ms', 's', 'min', 'h'];
  const baseUnitValue = [1,1000,1000*60,1000*60*60]
  const formatValue = Math.floor(timeValue / 1000);
  let resIndex;
  if (formatValue < 1) {
    resIndex = 0
  } else {
    const value = Math.floor(Math.log(formatValue) / Math.log(60)) + 1;
    resIndex = value > 3? 3: value
  }
  let resValue = timeValue / baseUnitValue[resIndex]
  if (resValue.toString().length > resValue.toFixed(2).length) {
    resValue = resValue.toFixed(2);
  }
  return `${resValue} ${baseUnitLabel[resIndex]}`;
};

3. 终版

思路: 引入findLastIndex及Math.max代提if/else;Number方法可以自动将诸如'2.00'转换成2;

优点:代码更简洁、可读性更强

export const timeConvert = function (timeValue) {
    if (!(typeof timeValue === "number" && timeValue >= 0)) {
        return "";
    }

    const baseUnitLabel = ["ms", "s", "min", "h"];
    const basicValue = [1, 1000, 1000 * 60, 1000 * 60 * 60];

    let index = Math.max(basicValue.findLastIndex(basic => timeValue >= basic), 0)
    
    return `${Number((timeValue / basicValue[index]).toFixed(2))} ${baseUnitLabel[index]}`;
};

三、知识点总结

1. Math.log

比如字节数的转换,就可以利用Math.log(bytes)/Math.log(1024)将其和单位的映射对应起来。

适应场景:适合相邻单位换算关系倍数固定的场景

2. findLastIndex

const da = [1,2,3,4,5]
const sa = da.findLastIndex(item => item < 4) // 2

如果找不到符合的值,返回-1;

结合上述案例

 let index = Math.max(basicValue.findLastIndex(basic => timeValue >= basic), 0)

相当于 

if (exp1 < 1) {
    exp2 = 0
  } else if (exp1 < 60) {
    exp2 =  1
  } else if(exp1 < 60 * 60)  {
    exp2 = 2
  } else {
    exp2 = 3
  }

为什么用findLastIndex,而不用findIndex是为了缩小范围,找到确定的值,如果最大下标对应的值符合条件,则返回。

3. 为什么用Number?

return `${Number((timeValue / basicValue[index]).toFixed(2))} ${baseUnitLabel[index]}`;

原因: 因为tofix(2)已经转换成字符串了,且有可能有诸如2.003转换成2.00的形式,2.00的格式不准确,应为2。 

而Number('2.00')可以转换成2,省去了如下的判断

if (resValue.toString().length > resValue.toFixed(2).length) {
    resValue = resValue.toFixed(2);
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值