cosyer's Blog

Blog


  • 首页

  • 友链

  • 留言板

  • 归档

  • 关于

  • 搜索

知识 分类

12月
15
更新于
12月15
2018
知识

java -jar与nohup

发表于 2018-11-13 | 热度 ℃
| 字数统计: 736 (字) | 阅读时长: 3 (分钟)

java程序员,经常会遇到这样一个问题,打个jar包,测试或者上线生产,于是乎面临的选择来了,java –jar or nohup? 下面我来扒一扒:

java -jar a.jar &

直接启动jar文件,在当前会话进程中开启一个子进程来运行程序,这个子进程会随着会话进程的结束而结束。

这种情况适合短时间测试用。

nohup java -jar a.jar &

hangup :(挂断),终端退出时会发送 hangup 信号来通知其关闭所有子进程。

nohup :(不挂断,忽略挂断信号)。

nohup 的使用是十分方便的,只需在要处理的命令前加上 nohup 即可,标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般我们可在结尾加上”&”来将命令同时放入后台运行,也可用”>filename2>&1”来更改缺省的重定向文件名。

这种情况适合在生产环境长时间运行。

nodejs应用在linux上运行

使用场景

  • forever管理多个站点,每个站点访问量不大,不需要监控。
  • supervisor是开发环境用。
  • nodemon 是开发环境使用,修改自动重启。
  • pm2 网站访问量比较大,需要完整的监控界面。
  1. forever

    1
    2
    3
    4
    5
    6
    npm install -g forever
    forever start index.js -o out.log -e err.log
    forever list
    forever stop index.js [id]
    forever stopall
    forever restartall
  2. supervisor 热部署

    1
    2
    npm install -g supervisor
    supervisor app.js // 文件有改动会立即重启node模块
  3. nodemon

    1
    2
    npm install -g nodemon
    nodemon app.js
  4. nohup

    1
    2
    nohup node index.js &
    nohup node index.js > myLog.log 2>&1 &

nohup问题:

但是有时候在这一步会有问题,当把终端关闭后,进程会自动被关闭,查看nohup.out可以看到在关闭终端瞬间服务自动关闭。 有个操作终端时的细节:当shell中提示了nohup成功后还需要按终端上键盘任意键退回到shell输入命令窗口,然后通过在shell中输入exit来退出终端; 而我是每次在nohup执行成功后直接点关闭程序按钮关闭终端。所以这时候会断掉该命令所对应的session,导致nohup对应的进程被通知需要一起shutdown。

  1. 高大上的pm2

特性:

  • 内建负载均衡(使用Node cluster 集群模块)
  • 后台运行
  • 0秒停机重载,维护升级的时候不需要停机
  • 具有Ubuntu和CentOS 的启动脚本
  • 停止不稳定的进程(避免无限循环)
  • 控制台检测
  • 提供 HTTP API
  • 远程控制和实时的接口API ( Nodejs 模块,允许和PM2进程管理器交互 )

使用:

1
2
3
4
5
6
7
8
9
npm install -g pm2
pm2 start app.js -o out.log -e err.log
pm2 stop app.js
pm2 restart app.js
pm2 list
pm2 descibe [id]
pm2 monit // 查看cpu和内存使用
pm2 logs // 实时集中log处理
pm2 web // 浏览器查看
7月
28
更新于
7月28
2020
知识

深浅拷贝

发表于 2018-10-31 | 热度 ℃
| 字数统计: 1,345 (字) | 阅读时长: 7 (分钟)

深浅拷贝概念

深拷贝和浅拷贝只针对象 Object, Array 这样的复杂对象(引用类型)的。

复制引用(引用类型)的拷贝方法称之为浅拷贝,创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果

属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝就是指完全的拷贝一个对象,将原对象的各个属性递归复制下来。这样即使嵌套了对象,两者也相互分离。

浅拷贝 对基本类型拷贝值,引用类型拷贝引用

Object.assign()

扩展运算符…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var shallowCopy = function(obj) {
if (typeof obj !== 'object') return; // 只拷贝对象
var newObj = obj instanceof Array ? [] : {}; // 根据obj的类型判断是新建一个数组还是对象
for (var key in obj) { // 遍历obj,并且判断是obj的属性才拷贝
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}

function shallowCopy2(source) {
if (source === null || typeof source !== 'object') return source;
const copy = Array.isArray(source) ? [] : {};

Object.keys(source).forEach(key => {
copy[key] = source[key];
});
return copy;
}

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
shallowObj.arr[1] = 5;
console.log(obj.arr[1]) // 5 互相影响 指向了同一块内存地址
shallowObj.a = 5;
console.log(obj.a) // 1

深拷贝(将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。)

JSON.parse(JSON.stringify(a)): 性能最快

具有循环引用的对象时,报错 当值为函数、undefined、或symbol时,无法拷贝

递归复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 不考虑循环引用
var deepCopy = function(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
shallowObj.arr[1] = 5;
console.log(obj.arr[1]) // 3 没有影响 重新拷贝了新数据
shallowObj.a = 5;
console.log(obj.a) // 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 不考虑循环引用
const clone = function(data){
if(typeof data !== 'object'){
return data;
}
let keys = Object.keys(data);
let result = Array.isArray(data) ? [] : {};
keys.forEach(key=>{
if(typeof data[key] === 'object'){
result[key] = clone(data[key]);
}else{
result[key] = data[key];
}
})
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 考虑循环引用 只考虑了普通的 object和 array两种数据类型
const clone = function(data){
let map = new WeakMap(); // 这里用WeakMap弱引用,会自动回收,不需要手动处理置为null
function dp(obj){
if(typeof obj !== 'object'){
return obj;
}
let o = map.get(obj);
if(o){
return o;
}
let result = Array.isArray(obj) ? [] : {};
map.set(obj, result);
let keys = Object.keys(obj);
keys.forEach(key=>{
if(typeof obj[key] === 'object'){
result[key] = dp(obj[key]);
}else{
result[key] = obj[key];
}
})
return result;
}
return dp(data);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 终极版
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';
const argsTag = '[object Arguments]';

const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';

const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];


function forEach(array, iteratee) {
let index = -1;
const length = array.length;
while (++index < length) {
iteratee(array[index], index);
}
return array;
}

function isObject(target) {
const type = typeof target;
return target !== null && (type === 'object' || type === 'function');
}

function getType(target) {
return Object.prototype.toString.call(target);
}

function getInit(target) {
const Ctor = target.constructor;
return new Ctor();
}

function cloneSymbol(targe) {
return Object(Symbol.prototype.valueOf.call(targe));
}

function cloneReg(targe) {
const reFlags = /\w*$/;
const result = new targe.constructor(targe.source, reFlags.exec(targe));
result.lastIndex = targe.lastIndex;
return result;
}

function cloneFunction(func) {
const bodyReg = /(?<={)(.|\n)+(?=})/m;
const paramReg = /(?<=\().+(?=\)\s+{)/;
const funcString = func.toString();
if (func.prototype) {
const param = paramReg.exec(funcString);
const body = bodyReg.exec(funcString);
if (body) {
if (param) {
const paramArr = param[0].split(',');
return new Function(...paramArr, body[0]);
} else {
return new Function(body[0]);
}
} else {
return null;
}
} else {
return eval(funcString);
}
}

function cloneOtherType(targe, type) {
const Ctor = targe.constructor;
switch (type) {
case boolTag:
case numberTag:
case stringTag:
case errorTag:
case dateTag:
return new Ctor(targe);
case regexpTag:
return cloneReg(targe);
case symbolTag:
return cloneSymbol(targe);
case funcTag:
return cloneFunction(targe);
default:
return null;
}
}

function clone(target, map = new WeakMap()) {

// 克隆原始类型
if (!isObject(target)) {
return target;
}

// 初始化
const type = getType(target);
let cloneTarget;
if (deepTag.includes(type)) {
cloneTarget = getInit(target, type);
} else {
return cloneOtherType(target, type);
}

// 防止循环引用
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);

// 克隆set
if (type === setTag) {
target.forEach(value => {
cloneTarget.add(clone(value, map));
});
return cloneTarget;
}

// 克隆map
if (type === mapTag) {
target.forEach((value, key) => {
cloneTarget.set(key, clone(value, map));
});
return cloneTarget;
}

// 克隆对象和数组
const keys = type === arrayTag ? undefined : Object.keys(target);
forEach(keys || target, (value, key) => {
if (keys) {
key = value;
}
cloneTarget[key] = clone(target[key], map);
});

return cloneTarget;
}

module.exports = {
clone
};

尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。

9月
07
更新于
9月07
2020
知识

js判断数据类型

发表于 2018-10-31 | 热度 ℃
| 字数统计: 541 (字) | 阅读时长: 3 (分钟)

typeof

typeof一般只能返回如下几个结果:number,boolean,string,function,object,undefined字符串

对于Array,null等特殊对象使用typeof一律返回object,这正是typeof的局限性。

typeof表示是对某个变量类型的检测,基本数据类型除了null都能正常的显示为对应的类型,引用类型除了函数会显示为’function’,其它都显示为object。

1
2
3
var fn = new Function ('a', 'b', 'return a + b')

typeof fn // function

instanceof

instanceof适用于检测对象,它是基于原型链运作的。

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。换种说法就是如果左侧的对象是右侧对象的实例, 则表达式返回true, 否则返回false 。

instanceof对基本数据类型检测不起作用,因为基本数据类型没有原型链。可以准确的判断复杂数据类型。

1
2
3
4
5
6
7
8
9
10
11
[1, 2, 3] instanceof Array // true 
/abc/ instanceof RegExp // true
({}) instanceof Object // true
(function(){}) instanceof Function // true

// 基于constructor
a.constructor === Array;
// 基于Object.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(a);
// 4.基于getPrototypeOf
Object.getPrototypeOf(a) === Array.prototype;

Object.prototype.toString.call

可以检测各种数据类型,推荐使用。

1
2
3
4
5
6
7
8
9
10
Object.prototype.toString.call([]); // => [object Array] 
Object.prototype.toString.call({}); // => [object Object]
Object.prototype.toString.call(''); // => [object String]
Object.prototype.toString.call(new Date()); // => [object Date]
Object.prototype.toString.call(1); // => [object Number]
Object.prototype.toString.call(function () {}); // => [object Function]
Object.prototype.toString.call(/test/i); // => [object RegExp]
Object.prototype.toString.call(true); // => [object Boolean]
Object.prototype.toString.call(null); // => [object Null]
Object.prototype.toString.call(); // => [object Undefined]
1
2
3
4
5
6
7
8
9
let isType = type => obj => {
return Object.prototype.toString.call( obj ) === '[object ' + type + ']';
}

var isString = isType( 'String' );
var isArray = isType( 'Array' );
var isNumber = isType( 'Number' );

console.log( isArray( [ 1, 2, 3 ] ) ); //true

constructor

constructor也不是保险的,因为constructor属性是可以被修改的,会导致检测出的结果不正确。

1
2
3
4
5
6
7
8
9
10
11
12
console.log([].constructor === Array)   // true
function a() {}
console.log(a.constructor === Function) // true
console.log(12.constructor === Number) // true
console.log('22'.constructor === String) // true
console.log([] .constructor === Array) // true
console.log({a: 1}.constructor === Object) // true
console.log(true.constructor === Boolean) // true
console.log(json.constructor === Object) // true
console.log((new Date()).constructor === Date) // true
console.log(reg.constructor === RegExp) //true
console.log(error.constructor === Error) // true
8月
24
更新于
8月24
2020
知识

js创建对象实现继承

发表于 2018-10-31 | 热度 ℃
| 字数统计: 3,327 (字) | 阅读时长: 15 (分钟)

今天10月31日,万圣节前夜。希望ff的病早点好,身体健康。

创建对象(字面量、构造函数、create方法、调用函数返回对象)

1
2
3
4
5
6
7
8
9
var obj = {} // 字面量 
var obj = new Object() // 很少见,性能低 没有形参时可省略()
var obj = Object.create(null) // 以xx为原型创建对象
var obj = Object.assign({}) // 复制到目标对象
// Object.assign()还可以去除多余的参数覆盖
Object.assign({ a: 1, b: 2 }, { b: 3, c: 3 })
const newObj = { ...{ a: 1, b: 2 }, ...{ b: 3, c: 3 } }
// {a: 1, b: 3, c: 3}
// Object() ==> {}

阅读全文 »
8月
29
更新于
8月29
2020
知识

实现jsonp

发表于 2018-10-30 | 热度 ℃
| 字数统计: 613 (字) | 阅读时长: 3 (分钟)

作为常用的跨域解决方案,怎么能不用原生实现一下呢!

jsonp跨域其实也是JavaScript设计模式中的一种代理模式。 在html页面中通过相应的标签从不同域名下加载静态资源文件是被浏览器允许的,所以我们可以通过这个“犯罪漏洞”来进行跨域。 一般,我们可以动态的创建script标签,再去请求一个带参网址来实现跨域通信。补充一点,JSONP不使用XMLHttpRequest对象加载资源,不属于真正意义上的AJAX。

1
2
3
4
5
6
7
8
9
// 实现目标
JSONP(url, {
data: {
key1: value1
},
callback: function (data) {
// data 是服务端返回的数据
}
})

阅读全文 »
7月
22
更新于
7月22
2020
知识

babel的.babelrc配置

发表于 2018-10-29 | 热度 ℃
| 字数统计: 488 (字) | 阅读时长: 2 (分钟)

Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。Babel 内部所使用的语法解析器是 Babylon

一个基本的.babelrc配置:

1
2
3
4
5
6
7
{
"presets": [
"env",
"stage-0"
],
"plugins": ["transform-runtime"]
}

阅读全文 »
12月
15
更新于
12月15
2018
知识

实现trim的3种方法

发表于 2018-10-29 | 热度 ℃
| 字数统计: 218 (字) | 阅读时长: 1 (分钟)

trim 方法 (字串) (JavaScript) 移除字串前后的空白字元以及行结束字元。

  • 用法 string.trim()
  1. 递归截取(不推荐)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function trim(str){
    // 加入类型判断
    if(str[0]===' '||str[str.length-1]===' '){
    if(str[0]===' '){
    str=str.substring(1,str.length)
    }
    if(str[str.length-1]===' '){
    str=str.substring(0,str.length-1)
    }
    trim(str)
    }else{
    console.log(str)
    return str
    }
    }
  2. 2次遍历记录不为空格的索引,最后截取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function trim(str) {
    let start, end // 开始和结束为止 遍历记录不为空格的索引
    for (let i = 0; i < str.length; i++) {
    if (str[i] !== ' ') {
    start = i
    break
    }
    }
    for (let i = str.length - 1; i > 0; i--) {
    if (str[i] !== ' ') {
    end = i
    break
    }
    }
    return str.substring(start, end + 1)
    }
  3. 正则替换

    1
    2
    3
    4
    5
    6
    7
    function trim(str) {
    return str.replace(/(^\s*)|(\s*$)/g, "")
    }

    // 1. value.toString()
    // 2. String('123213')
    // 3. '' + value
2月
20
更新于
2月20
2019
知识

console控制台优化

发表于 2018-08-30 | 热度 ℃
| 字数统计: 494 (字) | 阅读时长: 2 (分钟)

熟悉前端的不会对console和alert陌生,两者在调试的时候可谓是法宝级别的工具,但是关于console,其实远远不止于console.log这一个简单的命令,它能做的事情有很多,那么让我们来一起了解一下,它有哪些冷门功能吧。


阅读全文 »
7月
28
更新于
7月28
2020
知识

移动端web问题总结(长期更新)

发表于 2018-08-21 | 热度 ℃
| 字数统计: 822 (字) | 阅读时长: 3 (分钟)

meta基础知识

H5页面窗口自动调整到设备宽度,并禁止用户缩放页面

1
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />

ios竖屏拍照上传,图片被旋转问题

1
2
3
4
5
6
7
// 1.通过第三方插件exif-js获取到图片的方向
// 2.new一个FileReader对象,加载读取上传的图片
// 3.在fileReader的onload函数中,得到的图片文件用一个Image对象接收
// 4.在image的onload函数中,利用步骤1中获取到的方向orientation,通过canvas旋转校正,重新绘制一张新图
// 注意iPhone有3个拍照方向需要处理,横屏拍摄,home键在左侧,竖屏拍摄,home建上下
// 5.将绘制的新图转成Blob对象,添加到FormData对象中,然后进行校正后的上传操作
// 代码有点杂,待整理后上传,网上应该是可以找到的

ios:DOM元素固定一边,另一边滚动,滚动很卡的问题

1
2
// (横向滚动用的多些)简单粗暴的办法,样式添加如下属性
-webkit-overflow-scrolling: touch;

部分手机第三方输入法会将页面网上挤的问题

1
2
3
4
5
6
// 特定需求页面,比如评论页面,输入框在顶部之类的
const interval = setInterval(function() {
document.body.scrollTop = 0;
}, 100)
// 注意关闭页面或者销毁组件的时候记得清空定时器
clearInterval(interval);

iPhoneX适配

1
2
3
4
5
6
7
8
9
10
11
12
13
// 1.viewport meta 标签增加属性viewport-fit=cover
<meta name="viewport" content="width=device-width, viewport-fit=cover, xxxx">
// 2.body元素增加样式
body {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
// 3.如有fixed底部的元素,也增加上面样式
xxx {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
background-color: #fff; // 记得添加background-color,不然会出现透明镂空的情况
}

某些机型不支持video标签的poster属性,特别是安卓

1
2
3
用图片元素 <img />来代替poster
播放前显示<img />,隐藏 <video />
播放后显示<video />,隐藏 <img />

CSS透明度颜色设置问题

1
2
Android部分不支持 hex写法,推荐用rgba的写法
#0000009c --> rgba(0, 0, 0, 0.61)

flex对低版本的ios和Android的支持问题

1
2
3
4
5
6
7
8
// 使用postcss的autoprefixer插件,自动添加浏览器内核前缀,
// 并且增加更低浏览器版本的配置,自动添加flex老版本的属性和写法
autoprefixer({
browsers: [
'iOS >= 6', // 特殊处理支持低版本IOS
'Safari >= 6', // 特殊处理支持低版本Safari
],
}),

ios 页面回退到长列表出现灰色遮挡问题

1
2
3
4
5
6
方案1:对列表数据进行缓存,比如redux之类的用法。
方案2:回退时,跳到页面顶部。
const timer = setTimeout(() => {
window.scrollTo(0, 1);
window.scrollTo(0, 0);
}, 0);

ios 日期转换NAN的问题

1
2
将日期字符串的格式符号替换成'/'。
栗子:'yyyy-MM-dd'.replace(/-/g, '/')

react未知错误异常,导致页面崩溃,空白

1
2
React 16.x 增加了componentDidCatch() 生命周期方法
捕获全局异常来进行页面的友好提示

移动端适配

  • 媒体查询
  • px2rem
  • flexible
  • flex
  • grid
  • 百分比
9月
13
更新于
9月13
2020
知识

Http请求概述

发表于 2018-08-14 | 热度 ℃
| 字数统计: 4,714 (字) | 阅读时长: 17 (分钟)

超文本传输协议(HTTP, HyperText Transfer Protocol)是一种无状态的协议,它位于OSI七层模型的传输层。HTTP客户端会根据需要构建合适的HTTP请求方法,而HTTP服务器会根据不同的HTTP请求方法做出不同的响应。


阅读全文 »
12345
陈宇(cosyer)

陈宇(cosyer)

不去做的话永远也做不到。

159 日志
10 分类
51 标签
RSS
GitHub Twitter E-Mail FB Page
推荐阅读
  • Callmesoul
  • JsTips
  • Personal Site
  • Resume
© 2021 陈宇(cosyer)
终于等到你(UV):   |   欢迎再来(PV):
Blog总字数: 312.5k字
苏ICP备17005342号-1