@JunQiu
2020-12-29T14:06:43.000000Z
字数 3305
阅读 1326
summary_2018/08
language_js
docker
## 概述
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
Example:
const obj={
a:2
}
console.log(obj.a) // 2
const a = new Proxy(obj,{
get:function (target,pro) {
// 任何读均返回3
return 3
}
})
console.log(a.a) // 3
## 初始化
var proxy = new Proxy(target, handler)
// new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
// 小技巧:将proxy对象作为对象的属性
obj.proxy = new Proxy(obj, {
get: function (trget, pro) {
return 3
}
})
console.log(obj.proxy.a) // 3
## Proxy 支持的拦截操作
// get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。
// set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
// has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
// deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
// ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
// getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
// defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
// preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
// getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
// isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
// setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
// apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
// construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
## this问题
Proxy不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在Proxy代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。
// this的指向不同
const _name = new WeakMap();
class Person {
constructor(name) {
_name.set(this, name);
}
get name() {
return _name.get(this);
}
}
const jane = new Person('Jane');
jane.name // 'Jane'
const proxy = new Proxy(jane, {});
proxy.name // undefined
// 有些原生对象的内部属性,只有通过正确的this才能拿到,所以 Proxy 也无法代理这些原生对象的属性。可以绑定this对象实现(bind)
## Proxy.revocable():可取消的 Proxy 实例
let target = {}
let handler = {}
let {proxy, revoke} = Proxy.revocable(target, handler)
proxy.foo = 123
proxy.foo // 123
revoke()
proxy.foo // TypeError: Revoked
Tips:
1、dockerfile中的每一句命令都会生成一层layer,(from image的情况多层放到一层))(我们push/pull的时候能看到层数),且不会修改上一层。
2、docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。(docker history image 可以查看层的大小)
// 尽量减少镜像的层数,最好把移动、提取、删除等所有文件操作都写在同一行RUN命令下。因为每一条命令都会生成一层,每个镜像层都会占用一定的磁盘空间,且不会影响上一层。(比如weget下载,解压,删除多行的情况下,每层都会分别占有一定大小,见下图)
// 把update和清理命令都放在同一行RUN底下,在执行update的同时释放多余的空间(update会下载许多文件)
1、不要将数据储存在容器中:容器随时都可以停止、销毁或迁移
2、不要把镜像体积建得很大:镜像越大,就越难发布。镜像中只包含必要的文件和library就可以了
3、不要把认证口令存在镜像中,用环境变量比较好:可维护性
4、不要用root用户的角色来运行进程:安全性考虑
5、不要过分依赖IP地址:变化的
6、给镜像打tag的时候不要只打“latest"