当前位置: 欣欣网 > 码农

分享能提高开发效率,提高代码质量的八个前端装饰器函数~

2024-05-21码农


前言

大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心。分享一篇好文~

装饰器非常好用

前面给大家发了一篇文章xxx,给大家介绍了一遍JavaScript中的装饰器,今天就给大家介绍一下在我项目中用到过的几个装饰器的思路吧~

代码是伪代码,只是提供个思路,实际上代码不止这么少

防抖装饰器

当我们在一些特殊场景时,需要使用防抖这个优化手段来进行优化,比如:

  • 表单提交

  • 数据的搜索

  • 数据的筛选

  • 某些数据的更改

  • 数据改变时触发的回调

  • 这些函数都可以使用防抖装饰器来进行性能优化,防抖的意思是,当你频繁执行某一个操作时,这个操作只执行最后一次,确保不会因为频繁的执行而损耗性能~下面是装饰器的封装~

    // 装饰器的封装
    functiondebounce(delay{
    returnfunction(target, key, descriptor{
    const originalMethod = descriptor.value;
    let timer;
    descriptor.value = function(...args{
    clearTimeout(timer);
    timer = setTimeout(() => {
    originalMethod.apply(this, args);
    }, delay);
    };
    return descriptor;
    };
    }

    当我们某个函数需要进行防抖处理时

    @debounce(500)
    submit() {}
    @debounce(500)
    handleChange() {}
    @debounce(500)
    handleFilter() {}

    节流装饰器

    节流跟防抖是不同的优化手段,节流是保证在一段时间内只执行一次操作,适用在这些场景中:

  • 监听窗口宽度变化的回调

  • 监听滚动条变化的回调

  • 下面是装饰器的封装~

    functionthrottle(delay{
    returnfunction(target, key, descriptor{
    const originalMethod = descriptor.value;
    let timer;
    let lastExecTime = 0;
    descriptor.value = function(...args{
    const now = Date.now();
    if (now - lastExecTime >= delay) {
    lastExecTime = now;
    originalMethod.apply(this, args);
    else {
    clearTimeout(timer);
    timer = setTimeout(() => {
    originalMethod.apply(this, args);
    }, delay);
    }
    };
    return descriptor;
    };
    }

    当我们某个函数需要进行节流处理时

    @throttle(200)
    handleScroll() {}
    @throttle(200)
    handleResize() {}

    日志输出装饰器

    日志的输出是很重要的,尤其是在 Nodejs 端,日志输出会通过 pm2 等工具,记录在一些日志文件里,尤其是一些比较公用的工具函数,更是非常重要,一般需要记录这些内容

  • 执行的函数名称

  • 执行时传入的参数

  • 执行后获取到的结果

  • 下面是装饰器的封装~

    functionlog(target, key, descriptor{
    const originalMethod = descriptor.value;
    descriptor.value = function(...args{
    console.log(`Entering ${key} with arguments:`, args);
    const result = originalMethod.apply(this, args);
    console.log(`Exiting ${key} with result:`, result);
    return result;
    };
    return descriptor;
    }

    使用的时候

    classCommon{
    @log()
    commonRequest(url, params) {
    return request(url, params)
    }
    }
    const common = new Common()
    common.commonRequest('http://xxx.com', { name'l' })
    Entering commonRequest witharguments: ['http://xxx.com', { name'l' }]
    Exiting commonRequest with result: { 结果 }

    错误处理装饰器

    跟日志装饰器一样,错误其实也是日志的一部分,错误日志非常重要,因为 Nodejs 的线上报错,大部分都需要通过查日志来进行定位,所以我们也可以封装一个错误的处理装饰器~

    functionerrorHandler(target, key, descriptor{
    const originalMethod = descriptor.value;
    descriptor.value = function (...args{
    try {
    originalMethod.apply(this, args);
    catch (error) {
    console.error(`Error occurred in ${key}:`, error);
    }
    };
    return descriptor;
    }

    使用的时候

    classCommon{
    @log()
    commonRequest(url, params) {
    return request(url, params)
    }
    }
    const common = new Common()
    common.commonRequest('http://xxx.com', { name'l' })
    Error occurred in commonRequest: Request Error

    权限校验装饰器

    权限的校验在前端一般都不用装饰器,但是在 Nodejs 管理接口时,涉及到权限校验时,用装饰器是非常的方便的

    functionauthenticated(target, key, descriptor{
    const originalMethod = descriptor.value;
    descriptor.value = function(...args{
    if (isAuthenticated()) {
    originalMethod.apply(this, args);
    else {
    console.log('Unauthorized access!');
    }
    };
    return descriptor;
    }

    使用的时候,这样就只有 admin 的身份可以访问这个接口了~

    classUser{
    @Get('/xx/xx')
    @authenticated('admin')
    getUser() {}
    }

    计时装饰器

    如果有一天,你们需要埋点,计算一些比较重要函数的运行性能时,那么你肯定需要计算这些函数的执行时间是多少,这时候封装一个计时装饰器会让你非常方便~

    functiontiming(target, key, descriptor{
    const originalMethod = descriptor.value;
    descriptor.value = function(...args{
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`Execution time of ${key}${end - start} milliseconds`);
    return result;
    };
    return descriptor;
    }

    使用时

    classCommon{
    @timing()
    commonRequest(url, params) {
    return request(url, params)
    }
    }
    const common = new Common()
    common.commonRequest()
    Execution time of commonRequest: 20 milliseconds

    缓存装饰器

    这个装饰器适用在某一些场景,如果你有一个函数是用来计算值的,并且计算的过程非常复杂非常耗时间,那我建议你可以把这些计算结果储存起来,而不是每次都重新计算,这能大大提升你的计算性能~

    functioncache(target, key, descriptor{
    const originalMethod = descriptor.value;
    const cache = newMap();
    descriptor.value = function(...args{
    const cacheKey = JSON.stringify(args);
    if (cache.has(cacheKey)) {
    return cache.get(cacheKey);
    }
    const result = originalMethod.apply(this, args);
    cache.set(cacheKey, result);
    return result;
    };
    return descriptor;
    }

    使用时

    classCompute() {
    @cache()
    run(num1, num2) {
    // 这里举个简单例子
    return num1 + num2
    }
    }
    const c = new Compute()
    c.run(12// 3 首次计算
    c.run(12// 3 接下来都从缓存中拿

    参数校验装饰器

    在老项目中,无法用到 typescript 这么好的东西时,对于一些函数执行时,有必要用装饰器对传进来的参数的类型进行校验~没办法,没有 typescript 真难受啊~

    functionvalidateArgs(...types{
    returnfunction (target, key, descriptor{
    const originalMethod = descriptor.value;
    descriptor.value = function (...args{
    for (let i = 0; i < types.length; i++) {
    const type = types[i];
    const arg = args[i];
    if (typeof arg !== type) {
    thrownewError(`Invalid argument type at index ${i}`);
    }
    }
    originalMethod.apply(this, args);
    };
    return descriptor;
    };
    }

    使用的时候需要传入某个参数的类型限制

    classCommon{
    @validateArgs(['string''object'])
    commonRequest(url, params) {
    return request(url, params)
    }
    }
    const common = new Common()
    common.commonRequest(123123// 报错

    结语

    我是林三心

  • 一个待过 小型toG型外包公司、大型外包公司、小公司、潜力型创业公司、大公司 的作死型前端选手;

  • 一个偏前端的全干工程师;

  • 一个不正经的掘金作者;

  • 逗比的B站up主;

  • 不帅的小红书博主;

  • 喜欢打铁的篮球菜鸟;

  • 喜欢历史的乏味少年;

  • 喜欢rap的五音不全弱鸡

  • 如果你想一起学习前端,一起摸鱼,一起研究简历优化,一起研究面试进步,一起交流历史音乐篮球rap,可以来俺的摸鱼学习群哈哈,点这个,有7000多名前端小伙伴在等着一起学习哦 -->