ECMAScript 6中引入了相关 API —— Proxy
。
参考文档: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
搭配Reflect
使用例子:
var loggedObj = new Proxy(obj, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target,name, value, receiver);
if (success) {
console.log('property ' + name + ' on ' + target + ' set to ' + value);
}
return success;
},
get(target, name) {
console.log('get', target, name);
return Reflect.get(target, name);
},
deleteProperty(target, name) {
console.log('delete' + name);
return Reflect.deleteProperty(target, name);
},
has(target, name) {
console.log('has' + name);
return Reflect.has(target, name);
}
});
下面用例个示例来讲解何为优雅的元编程解决方案。
本章节以 腾讯云/QCloud 为例。
文档说明:https://www.qcloud.com/document/api/213/6978
请求形式:
https://cvm.api.qcloud.com/v2/index.php?
Action=DescribeInstances
&SecretId=xxxxxxx
&Region=gz
&Timestamp=1465055529
&Nonce=59485
&Signature=mysignature
&instanceIds.0=ins-0hm4gvho
&instanceIds.1=ins-8oby8q00
&offset=0
&limit=20
&status=2
&zoneId=100003
常规的解决方案大体如下:
class Cvm(){
constructor(config){
// 将配置信息传入进行初始化
this.hosts = 'https://cvm.api.qcloud.com/v2/index.php';
}
describeInstances(options){
// 查看实例列表为例
return request(this.hosts,{
action: 'describeInstances',
param1: options.param1
// 其他参数拼装
}).then(result=>{
return JSON.parse(result);
});
}
method2(options){
// 查看实例列表为例
return request(this.hosts,{
action: 'method2',
param1: options.param1
// 其他参数拼装
}).then(result=>{
return JSON.parse(result);
});
}
}
如果再有其他服务,再定义 class,再封装方法。
这类处理有一个特点就是,共性很多,都是发送 HTTP 请求,获取请求结果。差异化在于:
Action
// 引入 HTTP 请求相关封装库
import request from './request';
// 列举 API 别名,包括 QCloud CVM、CDN、CDB 等所有服务
const SDKS = ['bm', 'cdn', 'cdb', 'cvm', 'cbs', 'csec', 'dayu', 'lb', 'monitor', 'scaling', 'sqlserver', 'redis', 'cmem', 'trade', 'tdsql', 'vpc', 'wenzhi', 'yunsou'];
// 默认参数
const DEFAULTS = {
SecretId: '',
// Signature: '',
Region: 'gz',
Nonce: parseInt(Math.random() * 999999, 10),
Timestamp: parseInt(new Date() / 1000, 10)
};
const lazyLoad = service => (options) => {
// 设置各服务的 api host
const settings = {
api: `https://${service}.api.qcloud.com/v2/index.php`,
// 预留
actions: {}
};
// 重要事情说三遍:
// 核心代码开始
// 核心代码开始
// 核心代码开始
return new Proxy({}, { // 创建代理
// 定义 get 方法
// 例子:
// const obj = new Obj();
// obj.prop 获取属性,用的 get 方法
// obj.prop() 获取方法,用的依然是 get 方法
get: (target, property) =>
(opts) => {
// 非重要,将 Action 改为首字母大写,如 'ListRegions'
const action = property.replace(property.charAt(0), property.charAt(0).toUpperCase());
// 拼装请求参数
let params = Object.assign({}, DEFAULTS, options);
params = Object.assign({Action: property}, params, opts);
// 预留了 GET/POST 自定义
params.method = settings.actions[action] || 'post';
// 发送请求,获取请求结果返回
// 由于不同接口均是 HTTP/S 方式请求,只需将对应方法封装完成,即可实现复用
return request(settings.api, params);
}
});
};
// LazyLoad 懒加载优化性能,但对于元编程来讲收益并不太大
SDKS.forEach((item) => {
exports[item.toUpperCase()] = lazyLoad(item);
});
使用示例:
import {TRADE} from 'wqcloud';
const trade = TRADE(options);
// ES7 Async/Await 方式
(async() => {
const userInfo = await trade.DescribeUserInfo(params);
console.log(userInfo);
})();
// ES5 Promise 方式
trade.DescribeUserInfo(params).then((userInfo) => {
console.log(userInfo);
});