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);       

 

Javascript/ES6专题