當前位置: 妍妍網 > 碼農

分享能提高開發效率,提高程式碼品質的八個前端裝飾器函式~

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多名前端小夥伴在等著一起學習哦 -->