Javascript/ES6代理Proxy用法2
上页展示了ES6代理的两个用法,本页继续展示代理在实战中的应用。
安静记录对象的访问
一些方法可能是资源密集型,运行缓慢或时间比较长,我们需要记录它们的性能,Proxy代理可以在后台安静地记录。
let api = {
_apiKey: '123abc456def',
getUsers: function() { /* ... */ },
getUser: function(userId) { /* ... */ },
setUser: function(userId, config) { /* ... */ }
};
api = new Proxy(api, {
get: function(target, key, proxy) {
var value = target[key];
return function(...arguments) {
logMethodAsync(new Date(), key);
return Reflect.apply(value, target, arguments);
};
}
});
// executes apply trap in the background
api.getUsers();
function logMethodAsync(timestamp, method) {
setTimeout(function() {
console.log(`${timestamp} - Logging ${method} request asynchronously.`);
}, 0)
}
上面使用异步方法记录了你的代码可能会堵塞的地方,花不了多少代码就能时刻跟踪某个方法的性能。
警告或防止某些操作
如果你想阻止某人删除属性noDelete,你要让调用者知道oldMethod已经丢弃了,你要阻止任何人改变doNotChange属性:
let dataStore = {
noDelete: 1235,
oldMethod: function() {/*...*/ },
doNotChange: "tried and true"
};
const NODELETE = ['noDelete'];
const DEPRECATED = ['oldMethod'];
const NOCHANGE = ['doNotChange'];
dataStore = new Proxy(dataStore, {
set(target, key, value, proxy) {
if (NOCHANGE.includes(key)) {
throw Error(`Error! ${key} is immutable.`);
}
return Reflect.set(target, key, value, proxy);
},
deleteProperty(target, key) {
if (NODELETE.includes(key)) {
throw Error(`Error! ${key} cannot be deleted.`);
}
return Reflect.deleteProperty(target, key);
},
get(target, key, proxy) {
if (DEPRECATED.includes(key)) {
console.warn(`Warning! ${key} is deprecated.`);
}
var val = target[key];
return typeof val === 'function' ?
function(...args) {
Reflect.apply(target[key], target, args);
} :
val;
}
});
// these will throw errors or log warnings, respectively
dataStore.doNotChange = "foo";
delete dataStore.noDelete;
dataStore.oldMethod();
阻止不必要的重资源操作
假设你有一个服务器端点会返回一个非常大的文件,当之前有一个请求没有完成,或者文件正在下载,Proxy是一个好的缓冲机制,可以阻断用户对这个端点的重复请求。
let obj = {
getGiantFile: function(fileId) {/*...*/ }
};
obj = new Proxy(obj, {
get(target, key, proxy) {
return function(...args) {
const id = args[0];
let isEnroute = checkEnroute(id);
let isDownloading = checkStatus(id);
let cached = getCached(id);
if (isEnroute || isDownloading) {
return false;
}
if (cached) {
return cached;
}
return Reflect.apply(target[key], target, args);
}
}
});
立即撤销访问敏感数据
Proxy任何时候提供取消对目标原始对象的访问,这是在安全和性能保护时有用的,如下案例,使用revocable方法,注意当你使用它时,你不能在Proxy是new关键词。
let sensitiveData = {
username: 'devbryce'
};
const {sensitiveData, revokeAccess} = Proxy.revocable(sensitiveData, handler);
function handleSuspectedHack(){
// Don't panic
// Breathe
revokeAccess();
}
// logs 'devbryce'
console.log(sensitiveData.username);
handleSuspectedHack();
// TypeError: Revoked
console.log(sensitiveData.username);