分享能提高開發效率,提高代碼質量的八個前端裝飾器函數
裝飾器非常好用
前面給大家發了一篇文章xxx,給大家介紹了一遍JavaScript中的裝飾器,今天就給大家介紹一下在我項目中用到過的幾個裝飾器的思路吧!
代碼是偽代碼,只是提供個思路,實際上代碼不止這么少。
防抖裝飾器
當我們在一些特殊場景時,需要使用防抖這個優化手段來進行優化,比如:
- 表單提交
- 數據的搜索
- 數據的篩選
- 某些數據的更改
- 數據改變時觸發的回調
這些函數都可以使用防抖裝飾器來進行性能優化,防抖的意思是,當你頻繁執行某一個操作時,這個操作只執行最后一次,確保不會因為頻繁的執行而損耗性能~下面是裝飾器的封裝:
// 裝飾器的封裝
function debounce(delay) {
return function(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() {}
節流裝飾器
節流跟防抖是不同的優化手段,節流是保證在一段時間內只執行一次操作,適用在這些場景中:
- 監聽窗口寬度變化的回調
- 監聽滾動條變化的回調
下面是裝飾器的封裝:
function throttle(delay) {
return function(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 等工具,記錄在一些日志文件里,尤其是一些比較公用的工具函數,更是非常重要,一般需要記錄這些內容。
- 執行的函數名稱
- 執行時傳入的參數
- 執行后獲取到的結果
下面是裝飾器的封裝:
function log(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;
}
使用的時候:
class Common {
@log()
commonRequest(url, params) {
return request(url, params)
}
}
const common = new Common()
common.commonRequest('http://xxx.com', { name: 'l' })
Entering commonRequest with arguments: ['http://xxx.com', { name: 'l' }]
Exiting commonRequest with result: { 結果 }
錯誤處理裝飾器
跟日志裝飾器一樣,錯誤其實也是日志的一部分,錯誤日志非常重要,因為 Nodejs 的線上報錯,大部分都需要通過查日志來進行定位,所以我們也可以封裝一個錯誤的處理裝飾器:
function errorHandler(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;
}
使用的時候:
class Common {
@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 管理接口時,涉及到權限校驗時,用裝飾器是非常的方便的。
function authenticated(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 的身份可以訪問這個接口了。
class User {
@Get('/xx/xx')
@authenticated('admin')
getUser() {}
}
計時裝飾器
如果有一天,你們需要埋點,計算一些比較重要函數的運行性能時,那么你肯定需要計算這些函數的執行時間是多少,這時候封裝一個計時裝飾器會讓你非常方便。
function timing(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;
}
使用時:
class Common {
@timing()
commonRequest(url, params) {
return request(url, params)
}
}
const common = new Common()
common.commonRequest()
Execution time of commonRequest: 20 milliseconds
緩存裝飾器
這個裝飾器適用在某一些場景,如果你有一個函數是用來計算值的,并且計算的過程非常復雜非常耗時間,那我建議你可以把這些計算結果儲存起來,而不是每次都重新計算,這能大大提升你的計算性能。
function cache(target, key, descriptor) {
const originalMethod = descriptor.value;
const cache = new Map();
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;
}
使用時:
class Compute() {
@cache()
run(num1, num2) {
// 這里舉個簡單例子
return num1 + num2
}
}
const c = new Compute()
c.run(1, 2) // 3 首次計算
c.run(1, 2) // 3 接下來都從緩存中拿
參數校驗裝飾器
在老項目中,無法用到 typescript 這么好的東西時,對于一些函數執行時,有必要用裝飾器對傳進來的參數的類型進行校驗~沒辦法,沒有 typescript 真難受啊!
function validateArgs(...types) {
return function (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) {
throw new Error(`Invalid argument type at index ${i}`);
}
}
originalMethod.apply(this, args);
};
return descriptor;
};
}
使用的時候需要傳入某個參數的類型限制。
class Common {
@validateArgs(['string', 'object'])
commonRequest(url, params) {
return request(url, params)
}
}
const common = new Common()
common.commonRequest(123, 123) // 報錯