参考文档:
https://juejin.im/post/6844903667175260174
https://www.zhangxinxu.com/wordpress/2016/01/understand-css-stacking-context-order-z-index/?shrink=1
PM2 是一个带有负载均衡功能的Node应用的进程管理器
命令 | 说明 |
---|---|
pm2 start app.js | 启动进程/应用 |
pm2 start app.js –name wb123 | 重命名进程或应用 |
pm2 start bin/www –watch | 添加进程应用 watch |
pm2 stop www | 结束进程/应用 |
pm2 stop all | 结束所有应用 |
pm2 delete www | 删除进程/应用 |
pm2 delete all | 删除所有进程 |
pm2 list | 列出所有进程/应用 |
pm2 describe www | 查看某个进程或应用的具体情况 |
pm2 monit | 查看进程或应用的资源消耗情况 |
pm2 logs | 查看 pm2 日志 |
pm2 logs wwww | 查看某个进程/应用的日志 |
pm2 restart www | 重新启动进程/应用 |
pm2 restart all | 重新启动所有进程 |
pm2-dev start … | 启用开发调试 |
pm2 starup centos | 设置开机自启动 |
pm2 save | 保存设置 |
使用 Cluster 模块 实现
简易版 DEMO
1 | // master |
1 | // work |
pm2: Process manager for Node apps
pm2包括Satan进程,God Deamon 守护进程、进程间的远程调用rpc,cluster等几个概念.pm2中采用God Deamon 守护进程,God进程启动后一直运行, 它相当与cluster中的Master进程,守护者worker进程的正常运行
每次命令的输入都会执行一次satan程序, 如果God进程不再运行,首先需要启动God进程, 然后耕具指令, satan通过rpc调用God中对应的方法执行相应的逻辑
pm2 采用心跳检测查看子进程是否处于活跃状态
每隔数秒向子进程发送心跳包,子进程如果不回复,那么调用kill杀死这个进程,然后再重新cluster.fork()一个新的进程,子进程可以监听到错误事件,这个时候可以发送消息给主进程,请求杀死自己,并且主进程此时重新调用cluster.fork()一个新的子进程
pm2-dev start <appName>
1 | $> docker run -d --name pgdb -e POSTGRES_USER=sonar -e POSTGRES_PASSWORD=sonar -v ~/data/pgdata:/var/lib/postgresql/data-d docker.io/postgres:latest |
1 | $> docker volume create --name sonarqube_data |
1 | brew install sonar-scanner |
登录 sonarqube 网站 http://192.168.31.73:9000
在
Reflect.apply 和 Function#apply 很像, 他接收一个函数, 使用一个上下文对象和参数数组来调用该函数. 从这一点来说, 可以认为 Function#call 和 Function#apply 是过时的版本, 不过是更合理的说法.可以这样使用该方法.
1 | var ages = [11, 33, 12, 54, 18, 96]; |
Reflect.apply 相比 Function#apply 真正的好处在于其防御性: 任何代码都可以简单的修改函数 call 和 apply 方法,这使你应为崩溃的代码的可怕的变通方法而卡住. 这在一般情况喜爱并不是大问题, 但下面的代码可能真的存在
1 | function totalNumbers() { |
和 Refect.apply 类似, 这个方法用于一组参数来调用构造函数.这对于类也适用, 并且能够正确设置对象,从而让构造函数匹配原型的 this 对象.在 ES5 中,你是适用 Object.create(Construcor.prototype)的方法,然后将对象传给 Constructor.call 或 Constructor.apply. Refect.construct 的不同之处在于,并非传入对象, 只需要传入构造函数,然后 Refect.construct 会处理这些细节
1 | class Greeting { |
Reflect.defineProperty 和 Object.defineProperty 很想,用于定义属性的元数据(metadata).这个方法更适合,因为 Object.* 隐含着表示方法作用于对象字面量(其实是双抽象字面量构造函数), 而 Reflect.defineProperty 只表示现在做的反射有关,更具语义化
特别需要注意的是, 和 Object.defineProperty 一样,对于非法的 target, Reflect.defineProperty 会抛出 TypeError 异常, 例如 Number 或 String 类型(Reflect.defineProperty(1, ‘foo’)). 这是好事, 对于错误类型抛出异常而不是安静的失败,可以提醒你出现了问题
1 | function MyDate() { |
这个接口,可以视为 Object.getOwnPropertyDescriptor的替代,用于获取属性的描述元数据
主要的区别在于 Object.getOwnPropertyDescriptor(1,”foo”)只会静静的的失败,返回 undefined
而 Reflect.getOwnPropertyDescriptor(1, “foo”) 会抛出 TypeError
1 | var myObject = {}; |
Reflect.deleteProperty 会删除对象上的属性, 在 ES6 之前,你可能会写 delete obj.foo, 现在就可以用 Reflect.deleteProperty(obj, “foo”)
相同点: 都调用内部 target[Delete]方法.删除数据
不同点: delete 操作符还可以”用于”非对象的引用(例如,变量), 所以这个接口会做对操作对象进行更多的检查,也更可能的抛出异常
1 | var myObj = { foo: 'bar' }; |
关于替换,废弃 Object 方法的主题的继续
新的 Reflect.getPrototypeOf 对于非法的 target,会抛出 TypeError, 例如 Number, String 字面量, null 或 undefined.; 而 Object.getPrototypeOf 强制要求 target 是对象, 所以 “a” 会变成 Object(“a”)
1 | var myObj = new FancyThing(); |
Object.setPrototypeOf 对于非对象会抛出异常,但会尝试将传入的参数转为对象, 不过如果内部[[SetPrototype]] 方法失败,会抛出 TypeError, 成功则返回参数 target
Reflect.setPrototypeOf 则更基本一些,如果接收了一个非对象,则抛出 TypeError. 但如果 不是这样, 则会返回 [[SetPrototype]]的结果
1 | var myObj = new FancyThing(); |
在 ES6 之前, 如果传入了非对象, Object.isExtensible 会抛出异常 TypeError
在 ES6 之后, 传入了非对象, Object.isExtensible 会返回 false
而 Reflect.isExtensible 是使用了 ES6 之前 Object.isExtensible 的实现
1 | var myObject = {}; |
和 isExtensible 一样
ES5 和 Reflect 的实现一样,传入非对象抛出异常
ES6 Object.preventExtensions只是返回 true 或 false
1 | ar myObject = {}; |
用来调用 target[propertyKey].如果 target 不是一个对象, 函数报错,
而 1[‘foo’] 这样的代码只会静静的返回 undefined, 而 Reflect.get(1, ‘foo’) 会抛出 TypeError
Reflect.get 参数,在 target[propertyKey] 是一个 getter 函数时,会作为 this 参数应用
1 | var myObject = { |
和 Reflect.get 一样, 在 target[propertyKey]是 setter 函数时 将 receiver参数作为 this 使用
1 | var myObject = { |
和 in 操作符一样 都调用[[HasProperty]]方法,并在 target 不是对象的时候报错
1 | myObject = { |
Reflect.ownKeys 实现了[[OwnPropertyKeys]], 而后者是 Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols 的结合
1 | var myObject = { |
Hot Module Replacement (简称 HMR)
webpack-dev-middleware 调用 webpack 的api对文件系统watch, 当文件发生改变后,webpack重新对文件进行编译打包,然后保存到内存中.
webpack 将bundle.js 文件打包到内存中, 不生成文件的原因在于访问内存中的代码比访问文件系统中的文件更快,而且也减少了代码写入文件的开销
这一切都归功与mermory-fs, memory-fs是webpack-dev-middleware的一个依赖库,webpack-dev-middleware将webpack原本的outputFileSystem替换成了MemoryFileSystem实例, 这样代码就将输出到内存中.
webpack-dev-middleware 中该部分源码如下
1 | // compiler |
在启动devServer的时候,sockjs在服务器和浏览器端建立了一个websocket长连接,以便将webpack编译和打包的哥哥阶段状态告知浏览器, 最关键的步骤还是 webpack-dev-server调用webpack api监听 compile 的done 事件们当compile完成后,webpack-dev-server通过_sendStatus 方法将编译打包后的新模块hash值发送到浏览器端
1 | // webpack-dev-server/lib/Server.js |
webpack-dev-server 修改了pack配置中的entry属性,在里面添加了webpack-dev-client的代码,这样在最后bundle.js文件中就会接收到websocket消息的代码了
webpack-dev-server/client 当接收到type为hash消息后会将hash值暂存起来,当接收到type为ok的消息后对应用执行reload操作
在reload操作中,webpack-dev-server/client 会根据hot配置决定是刷新浏览器还是对当前代码进行热更新
1 | // webpack-dev-server/client/index.js |
首先 webpack/hot/dev-server (一下简称 dev-server) 监听第三步 webpack-dev-server/client发送的webpackHotUpdate消息,调用webpack/lib/HotModuleReplacement.runtime(简称HMR runtime)中的check方法,检测是否有新的更新
在check过程中会利用webpack/lib/JsonpMainTemplate.runtime (简称jsonp runtime)中的两个方法 hotDownloadManifest 和 hostDownloadUpdateChunk
hotDownloadManifest是调用Ajax 向服务端请求是否有更新的文件,如果有将发更新的文件列表返回浏览器端.该方法返回的是最新的hash值
hotDownloadUpdateChunk 是通过jsonp请求最新的模块代码,然后将代码返回给HMR runtime,HMR runtime 会根据返回的新模块代码做进一步处理,可能是刷新页面,也可能是对模块进行热更新.该方法返回的就是最新hash值对应的代码块
附: 为什么更新模块的代码不直接在第三步通过websocket 发送到浏览器端,而是通过jsonp来获取
功能块的解耦,各个模块各司其职,dev-server/client 只负责消息的传递而不负责新模块的获取,这些工作应该由 HMR runtime 来完成,HMR runtime 才应该是获取新代码的地方.再就是因为不适用 webpack-dev-server 的前提,使用 webpack-hot-middleware 和 webpack 配合也可以完成模块更新流程,在使用 webpack-hot-middleware 中有件有意思的事,他没有使用 websocket,而是使用 EventSource. 综上所述,HMR 的工作流中,不应该把新模块代码放在 websocket 消息中
这一步是整个模块热更新(HMR)的关键步骤,而且模块热更新都是发生在 HMR runtime 中的 HotApply 方法中
1 | // webpack/lib/HotModuleReplacement.runtime |
模块热更新的错误处理,如果在热更新过程中出现错误,热更新将回退到刷新浏览器,这部分代码在 dev-server 代码中,简要代码如下:
1 | module.hot.check(true).then(function(updatedModules) { |
当用新的模块代码替换老模块后,但是我们的业务代码不不知道代码已经发生变化,也就是说,当 hello.js 文件修改后,我们需要在 index.js 文件中调用 HMR 的 accept 方法,添加模块更新后的处理函数,及时将 hello 方法的返回值插入到页面中.代码如下
1 | // index.js |