• 高性能的js第三方库——lodash、 Underscore、async、md5及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函数

    【浅拷贝】:

    var objects = [{ 'a': 1 }, { 'b': 2 }];
     
    var shallow = _.clone(objects);
    console.log(shallow[0] === objects[0]);
    // => true

    如图:

     

      【深拷贝】:

      

    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

    //7.多维数组合并为一维数组
     _.flattenDeep([1, [2, [3, [4]]5]]);
    
    
     // => [1, 2, 3, 4, 5]
    //8.根据某个字段排序

    const users = [
    { 'user': 'fred', 'age': 48 },
    { 'user': 'barney', 'age': 34 },
    { 'user': 'fred', 'age': 42 },
    { 'user': 'barney', 'age': 36 }
    ];

    // 以 `user` 升序排序 再 以 `age` 降序排序。
    _.orderBy(users, ['user', 'age'], ['asc', 'desc']);

    // 9 .简单数组的排序

    _.sortBy(arr, function(item) {
      return item.createTime;
    });

    _.sortBy(arr, function(item) {
    return -item.createTime;
    });

    // 10.判断是否有重复

    _.uniq([2, 1, 2])
    // => [2, 1]

    if(_.uniq(arr) = arr.lengh){ // 判断去重后的数组长度

    }

    //补:其他引用写法:

    import {flattenDeep} from 'lodash' // 多维数组转换为一维数组
    
    

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

    // 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 += `
    ${res.info}`
        } else {
          this.loadingBuild = false
          this.loadingBuildResult = false
          this.$message.error(res.err_desc)
          this.buildResult = `打包失败:
    错误码:${res.error_code}
    ${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 = `打包失败:
    错误码:${res.error_code}
    ${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 = `打包超时:
    错误码:${res.error_code}
    ${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'
  • 相关阅读:
    GITHUB个人博客搭建-Pelican 在Windows环境下的安装及配置
    字符串-四则运算
    微信公众平台开发环境配置
    【小程序】使用uni-app搭建小程序环境---弹窗
    【小程序】使用uni-app搭建小程序环境---js变化
    【小程序】使用uni-app搭建小程序环境---组件标签
    【小程序】使用uni-app搭建小程序环境---封装接口
    【小程序】使用uni-app搭建小程序环境之框架
    【小程序】使用uni-app搭建小程序环境调用
    【js】JS Unicode编码和解码(6种方法)
  • 原文地址:https://www.cnblogs.com/wheatCatcher/p/11345141.html
Copyright © 2020-2023  润新知