2019-2-19lesson

Feb 19, 2019

记录最近学习nodejs

V8引擎 对类操作的加速

V8 引擎是google 邀请巴克为chrome 写的通用js底层引擎。
V8 创建类采用aClass = {},如果有新的属性,则会生成一个隐藏bClass = { this.name = “b” }, 同时将aClass 指向bClass。aClass 会因为js 的GC 技术稍后销毁。这将带来巨大的性能优化。

最佳做法:一次性声明aClass 属性,且尽量不要用 delete 方法。

CommonJS 类如何分割

web 全局有window,node 全局有global属性。相当于var a = 0;全局都会有a属性。
CommonJS 采用给每个被加载出来的js文件都变成某个函数:

1
2
3
4
(function() {
var a = 0;
var name = aKer;
})();

这时就变成一个个模块。

js 定义类的方法:

参考自:https://www.cnblogs.com/meteorcn/p/node_mianshiti_interview_question.html

pluz,我背诵上面的参考网址就去面试js了。运气爆棚。

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
构造函数方法定义类
function Person() {
this.name = "aKer"
}
Person.prototype.sayName = function () { alert(this.name) }
var person = new Person();
person.sayName()

对象创建方法定义类
var Person = {
name: "aKer",
sayName: function () { alert(this.name); }
}
var person = Object.create(Person);
person.sayName();

极简主义法(参考自 阮一峰博客), 推荐使用
var Cat = {
createNew: function() {
var cat = {};
cat.name = "aBai";
cat.makeSound = function () { alert("mmm"); };
return cat;
}
}
var cat1 = Cat.createNew();
cat1.makeSound();
这时继承就会如:
var Animal = {
createNew: function() {
var animal = {};
animal.sleep = function() { alert("sleep"); };
return animal;
}
}
var Cat = {
createNew: function() {
var cat = Animal.createNew();
cat.name = "aHei";
cat.makeSound = function() { alert("mmm"); };
return cat;
}
}
var cat1 = Cat.createNew();
cat1.sleep();

js类继承方法:

  • 原型链法
1
2
3
4
5
6
7
8
9
function Animal() {
this.name = "animal";
}
Animal.prototype.sayName = {
alert(this.name);
}
function Person() {}
Person.prototype = Animal.prototype;
Person.prototype.constructor = new Animal;
  • 属性自制法
1
2
3
4
5
6
function Person() {}

for (prop in Animal.prototype) {
Person.prototype[prop] = Animal.prototype[prop];
}
Person.prototype.constructor = "Person";//or new Person
  • 构造器应用法
1
2
3
function Person() {
Animal.call(this);
}

js常用设计模式:单例,工厂,代理,装饰,观察者模式

  • 单例

  • 工厂:同样形式参数返回不同实例

1
2
3
4
5
6
7
8
9
10
function Factory() {}
Factory.prototype.getInstance = function(className) {
return eval("new" + className + "()");
}
function Person() { this.name = "Person1"; }
function Animal() { this.name = "Animal1"; }

var factory = new Factory();
var person1 = factory.getInstance("Person");
var animal1 = factory.getInstance("Animal");
  • 代理

  • 观察者

实现一个简单的http服务器

1
2
3
4
5
6
var http = require("http");
http.createServer(function(req, res) {
res.writeHead(200, { "Content-Type": "text/html" });
res.write("aaa");
res.end();
}).listen(3000);

child_process

  • spawn
1
2
3
var cp = require("child_process");
var child = cp.spawn("echo", ["you", "hellow"]);
child.stdout.pipe(process.stdout);
  • fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fork-parent.js

var cp = require("child_process");
var child = cp.fork("./fork-child.js");
child.on("message", function(msg) {
console.log("parent get message from child", msg);
})
child.send("parent send msg to child");

fork-child.js

process.on("message", function(msg) {
console.log("child get msg from parent:", msg);
process.send("child send msg to parent to ask for money!");
})

判断用户密码时要注意什么

1
2
3
4
5
6
function checkApiKey(apiKeyFromDb, apiKeyReceived) {
if (apiKeyFromDb === apiKeyReceived) {
return true
}
return false;
}

比较密码时,不能泄露任何信息,因此比较必须在固定时间完成。否则,可以使用timing attacks来攻击你的应用。为什么会这样呢?Node.js使用V8引擎,它会从性能角度优化代码。它会逐个比较字符串的字母,一旦发现不匹配时就停止比较。当攻击者的密码更准确时,比较的时间越长。因此,攻击者可以通过比较的时间长短来判断密码的正确性。使用cryptiles可以解决这个问题:

1
2
3
4
function checkApiKey(apiKeyFromDb, apiKeyReceived)
{
return cryptiles.fixedTimeComparison(apiKeyFromDb, apiKeyReceived)
}

MySql 索引为什么SELECT 速度快

引自廖雪峰大大

索引的效率取决于索引列的值是否散列,即该列的值如果越互不相同,那么索引效率越高。反过来,如果记录的列存在大量相同的值,例如gender列,大约一半的记录值是M,另一半是F,因此,对该列创建索引就没有意义。\
\
可以对一张表创建多个索引。索引的优点是提高了查询效率,缺点是在插入、更新和删除记录时,需要同时修改索引,因此,索引越多,插入、更新和删除记录的速度就越慢。\
\
对于主键,关系数据库会自动对其创建主键索引。使用主键索引的效率是最高的,因为主键会保证绝对唯一。

随机生成密码方法

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
function randomString(length)
{
var charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var i;
var result = "";
var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
if(window.crypto && window.crypto.getRandomValues)
{
values = new Uint32Array(length);
window.crypto.getRandomValues(values);
for(i=0; i<length; i++)
{
result += charset[values[i] % charset.length];
}
return result;
}
else if(isOpera)//Opera's Math.random is secure, see http://lists.w3.org/Archives/Public/public-webcrypto/2013Jan/0063.html
{
for(i=0; i<length; i++)
{
result += charset[Math.floor(Math.random()*charset.length)];
}
return result;
}
else throw new Error("Your browser sucks and can't generate secure random numbers");
}

alert(randomString(10))

BDD/TDD 区别

此为其他处转载,忘记出处,侵权删

BDD是一种敏捷软件开发的技术。它对TDD的理念进行了扩展,在TDD中侧重点偏向开发,通过测试用例来规范约束开发者编写出质量更高、bug更少的代码。而BDD更加侧重设计,其要求在设计测试用例的时候对系统进行定义,倡导使用通用的语言将系统的行为描述出来,将系统设计和测试用例结合起来,从而以此为驱动进行开发工作。

柯里化函数

此为其他处转载,忘记出处,侵权删

ES 5的 bind()方法。
在pomelo的一些demo 里面可能会不理解这么一句话
session.on(‘closed’, onUserLeave.bind(null, this.app));

var onUserLeave = function(app, session) {
if(!session || !session.uid) {
return;
}
app.rpc.chat.chatRemote.kick(session, session.uid, app.get(‘serverId’), session.get(‘rid’), null);
};
你可能会有这样的疑问

  1. 为什么onUserLeave 会有两个参数?

  2. 函数的bind() 第一个参数null 什么什么意思,结合第一个问题,这里就传了一个参数?那么那个session 还是怎么传过来的?

    这个函数 bind() 方法是ES 5 新增的一个特性。用于将函数绑定到某个对象上。
    那么这里bind()的方法的作用是什么呢?
    要明白这里的bind()的用法,首先我们需要了解一种函数式编程技术—柯里化(currying)
    Wiki是这么定义的: 在计算机科学中,柯里化(Currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
    为了帮助理解这里写一个小例子(来自于Javascript 权威指南第六版 p191)
    var sum = function(x, y){
    return x+y;
    }
    //创建一个类似于sum的新函数,但this的值绑定到null
    //并且第一个参数绑定到1, 这个新函数的期望只传入一个实参
    var succ = sum.bind(null, 1);

console.log(succ(2)); //输出 3; x 绑定到1,并传入2作为实参

//另外一个做累计计算的函数
var sum2 = function(y ,z){
return this.x + y + z;
}

//绑定this 和 y
var bindSum2 = sum2.bind({x : 1}, 2);
console.log(bindSum2(3)); //输出 6; this.x 绑定到1,y绑定到2, z 绑定到3.
上面这个例子就是柯里化的应用了,现在我们回到pomelo看下,chatpomelo例子里面怎么使用这个柯里化技术。
现在,应该能解决开头的第一个问题了,那么第二个问题,我们需要阅读一下pomelo的源码
阅读源码sessionService.js 464-478
从这十几行代码和柯里化的知识,我们就能够明白为什么onUserLeave为什么会有两个参数了。
var onUserLeave = function(app, session){

}
最后的参数是通过柯里化的技术把单参数 session 传到我们多参数函数里面。

CentOS6 Nginx 配置免费ssl

Certbot

1
2
3
4
5
mkdir /root/download/
cd /root/download/
wget https://dl.eff.org/certbot-auto
#设置权限
chmod a+x certbot-auto

这时得到certbot-auto 文件夹

./certbot-auto –nginx #这里会对nginx 服务器配置,同时会对conf 文件修改
(中间出现ImportError: No module named virtualenv, $pip install virtualenv)

1
2
3
4
(certbot-auto renew 刷新)

//lsgood.top *.lsgood.top为我的域名,请填写自己的域名
certbot-auto certonly -d *.lsgood.top -d lsgood.top

修改nginx.conf:
server {
listen 443 default ssl;
server_name lsgood.top;
ssl on;
ssl_certificate xxxxxxxxx;#这个会被自动填写,是ssl 的公钥
ssl_certificate_key xxxxx;#同上,是ssl 的私钥

#其他不用设置可以

}

在设置 certbot 的时候需要注意碰到以下单词时,是需要到域名解析后台修改文件:

Please deploy a DNS TXT record under the name _acme-challenge.lsgood.com with the following value:\
\
xxxxxxxxxxxxxxx\
\
Before continuing, verify the record is deployed.

这意思是让你在继续下面之前,确保域名解析后台增加了以_acme-challenge 为前缀的子域名,同时将xxxxxxxxxxxxxxx 拷贝至里面的记录值一栏(记录类型为TXT)

参考:

https://juejin.im/post/5b07c42c51882538c2203b2f#heading-2

https://segmentfault.com/a/1190000017081357