高性能的js第三方库——lodash Underscoreasyncmd5及moment

Posted wheatcatcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高性能的js第三方库——lodash Underscoreasyncmd5及moment相关的知识,希望对你有一定的参考价值。

背景:为了实现某些功能,如:数据排序、分组、筛选、深拷贝等,自己写的函数或网上搜索处理的转换函数质量无法保证,这时直接使用成熟的js第三方库是首选。

*注:“framework(框架)”,“library(库)”和“tool(工具)” 可以根据情境,在不同时期,对不同的人,意味着不同的东西。

一、LodashUnderscore(推荐参考阮一峰的日志)

1.优点:将 Lodash 和 Underscore 放在一起,因为它们提供了数百个功能性的 javascript 实用程序来补充原生字符串,数字,数组和其他原始对象的方法。二者有一些功能性的重叠,所以你不太可能在一个项目中同事需要这两个库。

它在客户端使用率似乎很低,但是可以在服务器端的 Node.js 应用程序中使用这两个库。

  • 小而简单
  • 拥有优质文档,易于学习
  • 与大多数库和框架兼容
  • 不扩展内置对象
  • 可以在客户端或服务器上使用

2.缺点:

  • 有些方法只适用于ES2015及更高版本的 JavaScript

实例:

import * as _ from ‘lodash‘
import * as _s from ‘underscore‘

//数组去重对比
_.uniq([1,1,3])
// => [1,3]

_s.uniq([1, 2, 1, 4, 1, 3]);
=> [1, 2, 4, 3]

二、asyncmd5moment

分别是:异步请求、加密、日期转换

实例:

import * as _async from ‘async‘
import * as _moment from ‘moment‘
import * as _md5 from ‘md5‘

shunXuAsync()
  // 异步 顺序执行
  let task1 = function (callback) 

    console.log("task1");
    callback(null, "task1")
  

  let task2 = function (callback) 

    console.log("task2");
    callback(null, "task2")
    // callback("err","task2") // null改为err ,如果中途发生错误,则将错误传递到回调函数,并停止执行后面的函数
  

  let task3 = function (callback) 

    console.log("task3");
    callback(null, "task3")
  

  _async.series([task1, task2, task3], function (err, result) 
    console.log("series");
    if (err) 
      console.log(err);
    
    console.log(result);
  
  )


console.log(_moment().format(‘MMMM Do YYYY, h:mm:ss a‘)) //当前时间+格式

console.log(md5(‘message‘));//78e731027d8fd50ed642340b7c9a63b3

附:常用的几个Lodash函数

import _ from ‘lodash‘

// 1.深拷贝
var objects = [ ‘a‘: 1 ,  ‘b‘: 2 ];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

//2.分组
_.groupBy([6.1, 4.2, 6.3], Math.floor);
// =>  ‘4‘: [4.2], ‘6‘: [6.1, 6.3] 
 
// The `_.property` iteratee shorthand.
_.groupBy([‘one‘, ‘two‘, ‘three‘], ‘length‘);
// =>  ‘3‘: [‘one‘, ‘two‘], ‘5‘: [‘three‘] 

//3. 合并key、value
_.zipObject([‘a‘, ‘b‘], [1, 2]);
// =>  ‘a‘: 1, ‘b‘: 2 

//4.深比较不同
var object =  ‘a‘: 1 ;
var other =  ‘a‘: 1 ;
 
_.isEqual(object, other);
// => true
 
object === other;
// => false

//5.数组对象去重
var objects = [ ‘x‘: 1, ‘y‘: 2 ,  ‘x‘: 2, ‘y‘: 1 ,  ‘x‘: 1, ‘y‘: 2 ];
 
_.uniqWith(objects, _.isEqual);
// => [ ‘x‘: 1, ‘y‘: 2 ,  ‘x‘: 2, ‘y‘: 1 ]

//6.是否为空:对象、数组、布尔值、数值
_.isEmpty(null);
// => true
 
_.isEmpty(true);
// => true
 
_.isEmpty(1);
// => true
 
_.isEmpty([1, 2, 3]);
// => false
 
_.isEmpty( ‘a‘: 1 );
// => false

 对比一下,自己写一个异步请求函数需要怎么做:

// 1.分布打包请求
jarBuildChange(params) 
  this.buildResult = ‘‘
  this.loadingBuild = true
  this.loadingBuildResult = true
  const stepCallback = (res) => 
    console.log(res, ‘stepCallback‘)
    if (res.err_code === ‘0‘) 
      this.loadingBuildResult = false
      this.$message.success(‘日志已更新,正在打包中......‘)
      this.buildResult += `\\n$res.info`
     else 
      this.loadingBuild = false
      this.loadingBuildResult = false
      this.$message.error(res.err_desc)
      this.buildResult = `打包失败:\\n错误码:$res.error_code\\n$res.err_desc`
    
  
  const lastCallback = (res) => 
    console.log(res, ‘lastCallback‘)
    if (res.err_code === ‘0‘) 
      this.loadingBuild = false
      this.buildResult += `$res.err_desc`
      this.getBuildHistory()
      this.custom.jarname = res.jarname
      this.$message.success(‘打包结束,打包记录已更新!‘)
     else 
      this.loadingBuild = false
      this.loadingBuildResult = false
      this.$message.error(res.err_desc)
      this.buildResult = `打包失败:\\n错误码:$res.error_code\\n$res.err_desc`
    
  
  const timeoutCallback = (res) => 
    console.log(res, ‘timeoutCallback‘)
    this.loadingBuild = false
    this.loadingBuildResult = false
    this.getBuildHistory()
    this.$message.error(res.err_desc)
    this.buildResult = `打包超时:\\n错误码:$res.error_code\\n$res.err_desc`
  
  jarBuildResult(params, stepCallback, lastCallback, timeoutCallback)


//2.打包结果持续拉取:参数+开始返回+最后返回+超时返回
export function jarBuildResult(params, stepCallback, lastCallback, timeoutCallback) 
  stepRequest(_config.jarpackage_build, params || , stepCallback, lastCallback, 3600000, timeoutCallback)


//3.分布执行
export const stepRequest = (
  url, // 要封装调用接口路径
  data, // 封装调用接口请求数据
  stepCallback, // 中间步骤response回调,参数为response json
  lastCallback, // 调用最后response回调,参数为response json
  timeoutMs, // 执行超时时间
  timeoutCallback // 超时回调,无参数
) => 
  let nextSeqid = 0
  let isSuccDone = false
  let timeoutChecker = new TimeoutChecker(timeoutMs)

  let uuid = makeUuid()

  data[‘step_track_uuid‘] = uuid

  const doMainRequest = () => axios(
    url: url,
    method: ‘post‘,
    data: data,
    timeout: 3600000
  ).then(function (response) 
    return response
  ).catch(function (error) 
    console.log(error)
  )

  const handleResponseList = (stepRes) => 
    for (let response of stepRes.data.response_list) 
      // eslint-disable-next-line
      stepCallback(eval(‘(‘ + response + ‘)‘))
    
  

  const handleTimeout = () => 
    if (timeoutCallback) 
      let func = timeoutCallback
      timeoutCallback = null
      func()
    
  

  let interval = setInterval(() => 
    if (isSuccDone) 
      clearInterval(interval)
      handleTimeout()
     else 
      if (timeoutChecker.isTimeout()) 
        clearInterval(interval)
        handleTimeout()
       else 
        getResponseStepList(uuid, nextSeqid).then((stepRes) => 
          if (isSuccDone) 
            clearInterval(interval)
           else 
            nextSeqid = stepRes.data.next_seqid
            handleResponseList(stepRes)
          
        )
      
    
  , 2000)

  doMainRequest().then(res => 
    if (!timeoutChecker.isTimeout()) 
      isSuccDone = true
      clearInterval(interval)
      getResponseStepList(uuid, nextSeqid).then((stepRes) => 
        handleResponseList(stepRes)
        lastCallback(res.data)
      )
     else 
      handleTimeout()
    
  )

 生成随机数uuid:

function makeUuid () 
  var s = []
  var hexDigits = ‘0123456789abcdef‘
  for (var i = 0; i < 36; i++) 
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
  
  // bits 12-15 of the time_hi_and_version field to 0010
  s[14] = ‘4‘
  // bits 6-7 of the clock_seq_hi_and_reserved to 01
  s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1)
  s[8] = s[13] = s[18] = s[23] = ‘-‘

  var uuid = s.join(‘‘)
  return uuid

获取分布列表:

export const getResponseStepList = (uuid, seqid) =>
  axios.post(CONFIG_PREFIX + ‘/response/steplist‘, 
    step_track_uuid: uuid,
    step_next_seqid: seqid
  ).then(function (response) 
    return response
  ).catch(function (error) 
    console.log(error)
  )

axios异步封装:

import  CONFIG_PREFIX  from ‘./config‘
// import axios from ‘axios‘;
import axios from ‘./axios.js‘

/**
 * axios 配置
 * 请求超时
 * 登录携带cookie
 */
import axios from ‘axios‘// 让ajax携带cookie
import  doLogin  from ‘./login‘
import  Message  from ‘element-ui‘
import queryString from ‘query-string‘
import router from ‘../../src/router‘
// import Vue from ‘vue‘
axios.defaults.timeout = 3600000 // 请求超时
axios.defaults.withCredentials = true
function goNotAllowedPage () 
  // document.body.innerhtml = "<div id=‘app‘></div>"
  // let app = new Vue(
  //   el: ‘#app‘,
  //   template: ‘<div style="margin-top: 100px"><p style="text-align: center">暂无此模块权限,如需访问,请联系XXX申请权限。</p></div>‘
  // )

  // app.$destroy()
  router.push( path: ‘/web/notallowed‘ )

//* ************************************************ http request 请求拦截器
const parsed = queryString.parse(location.search)
axios.interceptors.request.use(
  config => 
    if (parsed.__test) 
      // e2e测试
      config.url = config.url.trim() + ‘?v__test=‘ + parsed.__test
    
    return config
  ,
  err => 
    return Promise.reject(err)
  
)

//* ******************************************** http response 返回拦截器
axios.interceptors.response.use(
  response => 
    if (response.status === 200 && response.data) 
      const res = response.data
      // 接口4001统一处理,4001意思是没有登录状态,需要重新登录
      if (res.err_code === ‘4001‘) 
        doLogin()
        // eslint-disable-next-line
        return Promise.reject("error");
       else if (res.err_code === ‘4003‘) 
        goNotAllowedPage()
        res.err_code = ‘0‘
        return response
       else if (res.err_code === ‘4005‘) 
        Message.error(‘请联系owner,无法进行修改‘)
        // eslint-disable-next-line
        return response;
       else if (res.app_config || res.err_code === ‘0‘) 
        // proj/app/get此请求无返回err_code=0
        return response
       else 
        // const desc = res.err_desc ? ‘操作失败错误,错误码:‘ + res.err_code + ‘,错误信息:‘ + res.err_desc : ‘返回值错误!‘;   //暂时注释
        // Message.warning(desc);
        return response
      
    
  ,
  error => 
    // console.log(error, ‘跨越问题无法获取状态码‘)
    if (error && error.response) 
      if (error.response.status === 400) 
        Message.error(‘请求错误(400)‘)
       else if (error.response.status === 404) 
        Message.error(‘请求出错(404)‘)
       else if (error.response.status === 408) 
        Message.error(‘请求超时(408)‘)
       else if (error.response.status === 500) 
        Message.error(‘服务器错误(500)‘)
       else if (error.response.status === 501) 
        Message.error(‘服务未实现(501)‘)
       else if (error.response.status === 502) 
        Message.error(‘网络错误(502)‘)
       else if (error.response.status === 503) 
        Message.error(‘服务不可用(503)‘)
       else if (error.response.status === 504) 
        Message.error(‘网络超时(504)‘)
       else 
        Message.error(`连接出错($error.response.status)!`)
      
     else 
      Message.error(error)
    
    return Promise.reject(error)
  
)

export default axios


//配置参数:
/** 【统一配置url入口】
 * 统一URL:cgi_domain_prefix
 * 代理URL(正式/测试)
 * 获取ticket:getPar(par)
 */
/* eslint-disable */
let cgi_domain_prefix = MY_HOST

// let cgi_domain_prefix=‘http://localhost:8080‘;

// if (process.env.NODE_ENV === ‘production‘) 
//     cgi_domain_prefix = "http://xxx:8080";
//  else 
//     cgi_domain_prefix = "http://xxx:8000";
// 

export const CONFIG_PREFIX = cgi_domain_prefix
//* **********************************************************************************************************
// 获取登录后的ticket:这里可以使用js第三方库【cookie.js】
function getPar (par) 
  // 获取当前URL
  // console.log("document.location.href", document.location.href)

  let local_url = document.location.href
  // 获取要取得的get参数位置
  let get = local_url.indexOf(par + ‘=‘)
  // console.log("document.location.href 2", document.location.href)

  if (get === -1) 
    return false
  
  // 截取字符串
  let get_par = local_url.slice(par.length + get + 1)
  // 判断截取后的字符串是否还有其他get参数
  let nextPar = get_par.indexOf(‘&‘)
  if (nextPar !== -1) 
    get_par = get_par.slice(0, nextPar)
  

  return get_par

const REAL_TICKER = getPar(‘ticket‘) ? ‘?ticket=‘ + getPar(‘ticket‘) : ‘‘

// 实例:
// 1.1.登录
export const GET_USER = cgi_domain_prefix + ‘/user/rtxname‘ + REAL_TICKER
// 1.2.注销
export const GET_LOGOUT = cgi_domain_prefix + ‘/user/logout‘

 

以上是关于高性能的js第三方库——lodash Underscoreasyncmd5及moment的主要内容,如果未能解决你的问题,请参考以下文章

lodash入门,使用 。throttle和debounce

JavaScript工具库——Lodash.js介绍安装及使用

DllPlugin - 打包性能优化点

Lodash一个一致性模块化高性能的JavaScript实用工具库

Lodash一个一致性模块化高性能的JavaScript实用工具库

「GoCN酷Go推荐」基于泛型的 Golang lodash 库 — samber/lo