您的位置:首页 > Web前端 > JavaScript

Js基础知识

2017-03-24 22:50 281 查看
npm install --save 与 npm install --save-dev 的区别

以npm安装msbuild为例:

npm install msbuild:

会把msbuild包安装到node_modules目录中
不会修改package.json
之后运行npm install命令时,不会自动安装msbuild

npm install --save:

会把msbuild包安装到node_modules目录中
会在package.json的dependencies属性下添加msbuild
之后运行npm install命令时,会自动安装msbuild到node_modules目录中
之后运行npm install --production或者注明NODE_ENV变量值为production时,会自动安装msbuild到node_modules目录中


npm install --save-dev:

会把msbuild包安装到node_modules目录中
会在package.json的devDependencies属性下添加msbuild
之后运行npm install命令时,会自动安装msbuild到node_modules目录中
之后运行npm install --production或者注明NODE_ENV变量值为production时,不会自动安装msbuild到node_modules目录中

使用原则:

运行时需要用到的包使用--save,否则使用--save-dev。

产品模式用dependencies,开发模式用devDep。

离线安装:

npm install --cache-min 9999999

安装nvm
首先下载nvm,这里我们需要使用Git,如果没有安装git,可以使用


sudo apt-get install git
git clone https://github.com/creationix/nvm.git ~/.nvm && cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`
接下来,我们需要编辑我们的环境变量配置文件
cd
vim .bashrc
将source ~/.nvm/nvm.sh  添加进我们的.bashrc中,保存退出。
输入命令
source  .bashrc
将新增的nvm添加到系统中。

nvm -v#查看nvm版本


nvm安装node版本

nvm install 7.8.0  // 安装
nvm use 5.0  // 切换
nvm uninstall 7.8.0  // 删除
nvm alias default 5.0  // 更换默认
npm install -g react-native-cli // 安装 react-native-cli 模块至全局目录,安装完成的路径是 ~/.nvm/versions/node/v4.4.7/lib/react-native-cli


Koa2 vs Flask

flask更适合做后端,因为flask的后端工具链更加成熟!!但koa2更能锻炼人。

ctx需要内置

this.methods的作用

是从第三方methods中的get获取的

http://ternjs.net/doc/manual.html

node.js写后端也是传输json数据,跟flask一样,但工具链不成熟(第三方,最重要是vim的跳转支持不成熟),总的来说没有flask做后端方便。但js语法比python语法友好多了,与C系语法更接近,再加上是前端不可或缺的语言,因此后端选择了js。

tern的配置不太可信!

term的配置是加载你每次打开的文件进行匹配,如果没有则不匹配。

property is enumerable javascript

总的来说

python适合数据分析建模,js适合大前端,c++适合高性能

基础:异步机制

  本节介绍JavaScript异步机制,首先来看一个例子:

for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
console.log(i);
  应该明白最后输出的全是5:

  1. i在此处是for循环所在上下文环境的变量,有且只有一个i;

  2. 循环结束时i==5;

  3. JavaScript单线程事件处理器在线程空闲前不会执行下一事件。

  需要真正明白以上三点,需要理解js的事件循环和并发模型。注意:回调和事件处理程序本质上并无区别,只是在不同情况下,不同的叫法。

  事件循环流程:

  1. 宿主环境为JavaScript创建线程时,会创建堆(heap)和栈(stack),堆内存储JavaScript对象,栈内存储执行上下文;(堆栈和队列的区别:1. 堆(heap):内存中某一未被阻止的区域,通常存储对象(引用类型); 2. 栈(stack):后进先出的顺序存储数据结构,通常存储函数参数和基本类型值变量(按值访问);
3. 队列(queue):先进先出顺序存储数据结构)

  2. 栈内执行上下文的同步任务按序执行,执行完即退栈,而当异步任务执行时,该异步任务进入等待状态(不入栈),同时通知线程:当触发该事件时(或该异步操作响应返回时),需向消息队列插入一个事件消息;

  3. 当事件触发或响应返回时,线程向消息队列插入该事件消息(包含事件及回调);

  4. 当栈内同步任务执行完毕后,线程从消息队列取出一个事件消息,其对应异步任务(函数)入栈,执行回调函数,如果未绑定回调,这个消息会被丢弃,执行完任务后退栈; 

  5. 当线程空闲(即执行栈清空)时继续拉取消息队列下一轮消息(next tick,事件循环流转一次称为一次tick)。

以上可描述为如下:

let async = function(sync, event) {
// 1.
// 2.
sync();
let eventLoop = [];
// 3.
eventLoop.push(event);
let i = eventLoop.length - 1; // 后进先出

while (eventLoop[i]) {
// 4.
event = eventLoop[--i];
if (event) { // 事件回调存在
event();
}
// 否则事件消息被丢弃
// 5.
}
};
  并发模型(Concurrency model)

  JavaScript异步编程使得多个任务可以并发执行,而实现这一功能的基础是JavScript拥有一个基于事件循环的并发模型。

let ele = document.querySelector('body');

function clickCb(event) {
console.log('clicked');
}

function bindEvent(callback) {
ele.addEventListener('click', callback);
}

bindEvent(clickCb);
  针对如上代码我们可以构建如下并发模型:



  如上图,当执行栈同步代码块依次执行完直到遇见异步任务时,异步任务进入等待状态,通知线程,异步事件触发时,往消息队列插入一条事件消息;而当执行栈后续同步代码执行完后,读取消息队列,得到一条消息,然后将该消息对应的异步任务入栈,执行回调函数;一次事件循环就完成了,也即处理了一个异步任务。

  再谈SETTIMEOUT(…0)

  了解了JavaScript事件循环后我们再看前文关于setTimeout(...0)的例子就比较清晰了:

  setTimeout(...0)所表达的意思是:等待0秒后(这个时间由第二个参数值确定),往消息队列插入一条定时器事件消息,并将其第一个参数作为回调函数;而当执行栈内同步任务执行完毕时,线程从消息队列读取消息,将该异步任务入栈,执行;线程空闲时再次从消息队列读取消息。

let start = +new Date();
let arr = [];

setTimeout(function() {
console.log('time: ' + (new Date().getTime() - start));
}, 10);
输出:

[master]$ node test.js
time: 30
  在setTimeout异步回调函数里我们输出了异步任务注册到执行的时间,发现并不等于我们指定的时间,而且两次时间间隔也都不同,考虑以下两点:

  1. 在读取消息队列的消息时,得等同步任务完成,这个是需要耗费时间的;

  2. 消息队列先进先出原则,读取此异步事件消息之前,可能还存在其他消息,执行也需要耗时;

  所以异步执行时间不精确是必然的,所以我们有必要明白无论是同步任务还是异步任务,都不应该耗时太长,当一个消息耗时太长时,应该尽可能的将其分割成多个消息。

  WEB WORKERS

  每个Web Worker或一个跨域的iframe都有各自的堆栈和消息队列,这些不同的文档只能通过postMessage方法进行通信,当一方监听了message事件后,另一方才能通过该方法向其发送消息,这个message事件也是异步的,当一方接收到另一方通过postMessage方法发送来的消息后,会向自己的消息队列插入一条消息,而后续的并发流程依然如上文所述。

  JavaScript异步实现

  关于JavaScript的异步实现,以前有:回调函数,发布订阅模式,Promise三类,而在ES6中提出了生成器(Generator)方式实现。

https模块

什么是CA:

  CA(Certificate Authority)是数字证书认证中心的简称,是指发放、管理、废除数字证书的机构。

  CA的作用是检查证书持有者身份的合法性,并签发证书(在证书上签字),以防证书被伪造或篡改,以及对证书和密钥进行管理。

SSL证书中DN(Distiguish Name)识别名的结构:

  遵循x.500标准,标识名的目的就是为每个网络实体提供一个唯一的名字。为了达到这一目的,DN有一种分层结构。一个DN由一些列的RDN(Relative distinguished name,相对标识名)构成。

  RDN的乘此结构依次为:

  C = US, ST = Beijing, L = Beijing, O = RTFM, OU = Consulting, CN = Eric

  (C->Country, ST-> State or  Provice Name, L->Locality Name, O->Organization, OU->Organization Unit, CN->Common Name)

创建自己的CA机构

为CA生成私钥:

openssl genrsa -out ca-key.pem -des 1024
通过CA私钥生成CSR:

openssl req -new -key ca-key.pem -out ca-csr.pem -subj "/C=CN/ST=Beijing/L=Beijing/O=Teamsun/OU=Teamsun"
通过CSR文件和私钥生成CA证书:
openssl x509 -req -days 3650 -in ca-csr.pem -signkey ca-key.pem -out ca-cert.pem


创建服务器端证书

为服务器生成私钥

openssl genrsa -out server-key.pem 1024
利用服务器私钥文件服务器生成CSR

openssl req -new -key server-key.pem -config openssl.cnf -out server-csr.pem


openssl req -new -key server-key.pem -config openssl.cnf -out server-csr.pem
这一步非常关键,你需要指定一份openssl.cnf文件。可以用这个[req]
    distinguished_name = req_distinguished_name
    req_extensions = v3_req

    [req_distinguished_name]
    countryName = Country Name (2 letter code)
    countryName_default = CN
    stateOrProvinceName = State or Province Name (full name)
    stateOrProvinceName_default = BeiJing
    localityName = Locality Name (eg, city)
    localityName_default = BeiJing
    organizationName = Organization Name (eg, company)
    organizationName_default = Teamsun
    organizationalUnitName = Organizational Unit Name (eg, section)
    organizationalUnitName_default = Letfl
    commonName = commonName (e.g. server FQDN or YOUR name)
    commonName_default = LetFl

    [ v3_req ]
    # Extensions to add to a certificate request
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName = @alt_names

    [alt_names]
    IP.1 = 127.0.0.1
    IP.2 = 192.168.1.6
通过服务器私钥文件和CSR文件生成服务器证书

openssl x509 -req -days 730 -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in server-csr.pem -out server-cert.pem -extensions v3_req -extfile openssl.cnf


创建客户端证书

生成客户端私钥

openssl genrsa -out client-key.pem 1024
利用私钥生成CSR

openssl req -new -key client-key.pem -out client-csr.pem -config openssl.cnf

生成客户端证书

openssl x509 -req -days 365 -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in client-csr.pem -out client-cert.pem


测试
1. 使用server证书测试单向认证
1.1 打开窗口1启动server


^o^$ 20:28:50 letfly@ [Js]$ openssl s_server -accept 10001 -key server-key.pem -cert server-cert.pem

Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT
1.2 打开窗口2启动客户端
^o^$ 20:28:50 letfly@ [Js]$ openssl s_client -connect localhost:10001

CONNECTED(00000003)
... ...
1.3 连接成功后在任意一个窗口输入字符串会传输到另外一个窗口回显。
2 使用server证书和客户端证书做双向测试

2.1 打开窗口1启动server。(带有Verify参数,强制要求client证书)

^o^$ 20:28:50 letfly@ [Js]$ openssl s_server -accept 10001 -key server-key.pem -cert server-cert.pem -Verify 5
2.2 打开窗口2启动客户端
^o^$ 20:28:50 letfly@ [Js]$ openssl s_client -connect localhost:10001 -cert client-crt.pem -key client-key.pem
2.3 双向证书正确则连接成功,否则连接失败。

2.4 通过控制台可以双向发送消息


HTTPS 服务器代码

const https = require('https');
const fs = require('fs');

let options = {
key: fs.readFileSync('./server-key.pem'),
ca: [fs.readFileSync('./ca-cert.pem')],
cert: fs.readFileSync('./server-cert.pem'),
requestCert: true,  // 双向认证
rejectUnauthorized: true,
};
https.createServer(options, function(req, res) {  res.writeHead(200);  res.end('hello world\n');}).listen(3000, '127.0.0.1');
HTTPS 客户端代码
const https = require('https');
const fs = require('fs');

let options = {
hostname: '127.0.0.1',
port: 3000,
path: '/',
method: 'GET',
key: fs.readFileSync('./client-key.pem'),
cert: fs.readFileSync('./client-cert.pem'),
ca: [fs.readFileSync('./ca-cert.pem')],
rejectUnauthorized: true,
};

options.agent = new https.Agent(options);
let req = https.request(options, function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
res.setEncoding('utf-8');
res.on('data', function(d) {
console.log(d);
});
});

req.end();

req.on('error', function(e) {
console.log(e);
});


Google Chrome,Mac OS X和自签名SSL证书

  这里是如何让Chrome浏览器使用自签名SSL证书:

1. 在地址栏中,点击X的小锁。这将显示一个小信息屏幕。单击说明“证书信息”的按钮。

2. 单击并将图像拖动到桌面。它看起来像一个小证书。

3. 双击它。这将启动钥匙串访问实用程序。输入您的密码解锁。

4. 确保将证书添加到系统钥匙串,而不是登录钥匙串。点击“始终信任”,即使这似乎没有任何作用。

5. 添加完成后,双击它。您可能需要再次进行身份验证。

6. 展开“信任”部分。

7. “使用此证书时”设置为“始终信任”

  而已!关闭钥匙串访问并重新启动Chrome,浏览器现在应该识别您的自签名证书。

  这是我希望Google / Chromium很快修复的一件事,因为它不应该是困难的。自签名的SSL证书在商业世界中被使用* 很多,对于知道他们正在做什么的人来说,应该有一个更简单的方法来忽略这个错误,而不是复制证书并手动将它们添加到系统钥匙串。

ws第三方

websocket基于http实现,http基于tcp实现

最初不经过https,为ws。文件为main.js

1.1 运行服务端ws实例

const WebSocketServer = require('ws').Server;
let wsserver = new WebSocketServer({ port: 3000 });

wsserver.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});

ws.send('something');
});
运行如下命令:

node main.js


1.2 运行客户端浏览器中的websocket实例

let socket = new WebSocket("ws://127.0.0.1:3000/");
socket.send('message');


加入https,为wss。

const fs = require('fs');
const https = require('https');
const WebSocketServer = require('ws').Server;

// 单向认证
let options = {
key: fs.readFileSync('./server-key.pem'),
cert: fs.readFileSync('./server-cert.pem')
};

let app = https.createServer(options, function(req, res) {
res.end('Hello world\n');
}).listen(3000, '127.0.0.1');

let wsServer = new WebSocketServer({ server: app });

wsServer.on('connection', function connection(socket) {
socket.on('message', function incoming(message) {
console.log('received: %s', message);
});

socket.send('something');
});


对象查找 

1.  避免对象的嵌套查询,因为JAVASCRIPT的解释性,a.b.c.d.e嵌套对象,需要进行4次查询,嵌套的对象成员会明显影响性能。

2.  如果出现嵌套对象,可以利用局部变量,把它放入一个临时的地方进行查询。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: