KevinSwift

  • 首页
  • 关于
  • 标签
  • 分类
  • 相册

docker学习(2)

发表于 2019-01-29 | 分类于 docker容器

docker部署node js应用

其实是创建一个node js项目的镜像,在镜像之上运行容器。
创建一个空文件夹,里面包含如下文件。
server.js package.json Dockerfile .dockerignore
命令如下

1
2
3
4
5
6
mkdir docker_demo
cd docker_demo
touch server.js
touch package.json
touch Dockerfile
touch .dockerignore

server.js是koa的主程序。写入如下代码。

1
2
3
4
5
6
7
8
const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
ctx.body = 'Hello docker';
});

app.listen(3000);

package.json是依赖项目文件。有以下配置。

1
2
3
4
5
6
7
8
9
10
11
{
"name": "docker_demo",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "node server.js"
},
"dependencies": {
"koa": "^2.5.0"
}
}

通过npm install和npm start便可在本地运行
dockerfile是由一系列命令和参数构成的脚本,一个dockerfile里面包含了构建整个image的完整命令,docker通过docker build来执行dockerfile中的一系列命令来创建image,在.dockerignore中写入如下代码,表示在构建的时候忽略这些文件。

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
# Logs
logs
*.log
npm-debug.log*

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules
jspm_packages

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history
.idea
.node_modules
node_modules
.vscode

在dockerfile中写入如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#制定node镜像的版本
FROM node:8.9.0-alpine
#声明作者
MAINTAINER robin
#移动当前目录下面的文件到app目录下
ADD . /app/
#进入到app目录下面,类似cd
WORKDIR /app
#安装依赖
RUN npm install
#对外暴露的端口
EXPOSE 3000
#程序启动脚本
CMD ["npm", "start"]

使用build命令构建镜像。注意后面那个.不能少。
是在当前docker_demo的文件夹下面

1
docker build -t docker_demo .

便可以创建镜像。
通过

1
docker riun -d -p 9000:3000 docker_demo

来基于该node镜像创建容器。
查看容器

1
docker ps

便可以通过访问本地端口9000来访问docker node容器。
参考博客

docker镜像迁移

在开发中,不免要进行镜像迁移。本机mac上的迁移到ubuntu或者windows上等。
首先打包镜像.

1
docker save  docker_demo | gzip > docker_demo-latest.tar.gz

表示打包形式为压缩包形式,名字为docker_demo-latest.tar.gz文件。
随后在装好了docker的其余主机上。加载镜像即可。

1
docker load -i docker_demo-latest.tar.gz

这样即可。在其余主机上创建镜像。并且以此镜像为基础创建容器。
参考博客
ubuntu上安装docker过程

docker学习(1)

发表于 2019-01-27 | 分类于 docker容器

docker介绍

docker是一个开源的引擎,可以为任何应用创建一个轻量级的,可移植的,自给自足的容器。
可以让开发者打包他们的应用以及他们的依赖包到一个轻量级,可移植的容器当中。然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙盒机制的,相互之间不会有任何的接口。类似iphone中的app,更重要的是容器性能开销极低。

docker应用场景

1.Web 应用的自动化打包和发布。
2.自动化测试和持续集成、发布。
3.在服务型环境中部署和调整数据库或其他的后台应用。
4.从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境。

docker架构

docker使用客户端-服务器(C/S)架构模式,使用远程api来管理和创建docker容器。
docker容器通过docker镜像来创建。
镜像相当于类,容器相当于类、
类似于如下图:

docker镜像(images):用于创建docker容器的模板
docker容器(containers):容器是独立运行的一个或一组应用
docker客户端(clients):通过命令行或者其他工具使用docker的API
docker主机(hosts):一个物理或者虚拟的机器用于执行docker守护进程和容器
docker仓库(regisity):仓库用来保存镜像。可以理解为代码控制中的代码仓库。

mac端安装

可以使用docker客户端或者使用brew install docker进行安装即可。

创建hello world

docker允许在容器内允许应用程序,使用docker run命令来在容器中运行一个应用程序.

1
docker run ubuntu:16.04 /bin/echo "hello world"

参数解析:
docker:docker的二进制执行文件
run:与前面的docker组合运行一个容器
ubuntu16.04:表示指定要运行的容器。首先从本地主机上查找镜像是否存在,如果不存在,docker便会从镜像库中下载
/bin/echo “hello world” 在启动的容器里执行命令
运行交互式的容器
-i -t 让docker运行的容器实现”对话”的能力。

1
docker run -i -t ubuntu:16.04 /bin/bash

-t:在新容器中指定一个伪终端或者终端
-i:允许对容器内的标准输入进行交互
启动容器(后台模式)
使用以下命令创建一个以进程方式运行的容器

1
docker run -d ubuntu:16.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"

输出为efc7e4901d5997dbd419aeb3086a0edf741b51f0a6dcf291ffa535d3e74bd172
这个长字符叫做容器的ID,对每个容器来说是唯一的。

1
docker ps

来查看容器的运行状态
container ID表示容器ID,names表示自动分配的容器的名称。

docker容器的使用

可以直接输入docker命令来查看docker客户端的所有命令。
运行一个web应用程序
以python为例
1.载入镜像

1
docker pull training/webapp  # 载入镜像

开始运行

1
docker run -d -P training/webapp python app.py

-d表示容器在后台运行 -P表示容器内部使用的网络端口映射到我们使用的主机上面

查看web应用程序

1
docker ps

来查看正在运行的容器
可以表明flask的5000端口映射到了本机的32768端口
访问localhost:32768便可以访问docker容器中的5000端口
使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。
docker port bf08b7f2cd89 也是根据容器的id来进行指定即可。
重启web容器

1
docker start wizardly_chandrasekhar

移除web应用程序

1
docker rm wizardly_chandrasekhar

注意 删除容器的时候,容器必须是停止状态,否则会报错。

docker指定端口

1
docker run -d --name = "ckq" -p 127.0.0.1:5001:5000 training/webapp python app.py

指定本机127.0.0.1:50001端口映射到容器内的5000端口,–name表示指定名字 -d表示后台运行。

es6学习(2)

发表于 2019-01-26 | 分类于 js相关

函数的相关学习

默认参数的基本用法。

1
2
3
4
function fn(name,age = 17) {
console.log(name + " " + age);
}
fn("Amy");

age参数可以不必进行传入而使用该函数
只有在没有传递参数,或者参数为undefined时候,才能使用默认参数,null值被认为是有效的传递.

1
fn("ckq",null);

该种情况age会输出为null

1
fn("ckq",undefined);

该种情况age会输出17,而不会输出undefined.

不定参数用来表示不确定的参数个数,形如 …变量名,有…加上一个具名参数标识符组成,具名参数只能放在参数组的最后,并且有且只有一个不定参数。

1
2
3
4
function f(...values) {
console.log(values.length);
}
f(1,2,3);

箭头函数
提供了一种更加简洁的函数书写方式,基本语法是
参数 => 函数体

1
2
var f = (v,x) => {return v * 2};
console.log(f(2,3));

当有多个参数的时候用括号包起来,当有多个执行语句的时候用{}包裹起来。
箭头函数里面是没有this对象的,此时的this对象是外层的this对象,即windows对象。

1
2
3
var func = () => {
console.log(this);
}

指的是windows这个对象。
定义函数的方法。且该方法中包含this变量,此时,this指向全局windows,所以定义方法的时候必须指定function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var person = {
"age":18,
'sayHello':() => {
console.log(this.age);
}
}
var age = 12;
person.sayHello();
var Person1 = {
'age': 18,
'sayHello': function () {
console.log(this.age);
}
};
var age = 20;
Person1.sayHello(); // 18

ES6迭代器

iterator是es6新引入的一种遍历机制,迭代器有两个核心概念。
1.迭代器是一个统一的接口,它的作用是使各种数据结构可被快捷的访问。它是通过一个键为Symbol.iterator来实现。
2.迭代器是用于遍历数据结构元素的指针(如数据库中的游标)
迭代的过程如下
1.通过Symbol.iterator创建一个迭代器,指向当前数据结构的起始位置
2.随后通过next方法进行向下迭代指向下一个位置,next方法回返回当前位置的对象,对象包含了value和done两个属性。value是当前属性的值,done用于判断是否遍历结束.
3.当done为true的时候,则遍历结束.
下面通过简单的例子来说明。

1
2
3
4
5
6
const items = ['zeros','one','two'];
const it = items[Symbol.iterator]();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

创建迭代器,随后不断的调用next方法对数组内部进行访问。当属性done为true时访问结束。
迭代器是协议的一部分,用于迭代,该协议的一个关键特性便是它是顺序的。迭代器一次返回一个值,这意味着如果可迭代数据结构是非线性的(例如树),则会转化成线性
以下是可迭代的数据结构array,string,map,set
for…of进行迭代循环。

1
2
3
for(let item of items){
console.log(item);
}

普通对象是无法进行迭代的,可以使用array.from来进行转化为可迭代对象.

1
2
3
4
const arrayLink = {length:2,0:"zero",1:"one"};
for(let item of Array.from(arrayLink)){
console.log(item);
}

class类

class(类)作为对象的模板被引入,可以通过class关键字定义类。
class的本质是function。可以看做是一个语法糖,让对象原型的写法更加清晰。更像面向对象编程的方法。
类的声明

1
2
3
4
5
6
7
8
let Example = class  {
constructor(a){
this.a = a;
}
}

let example = new Example(2);
console.log(example.a);

注意点:类的定义不会被提升,这意味着,必须在访问前对类进行定义,否则会报错。
constructor是默认的构造方法。instanceof判断两个对象是否相同。是属于同一个原型链的。

1
console.log(example instanceof Example);

extends方法用来继承

1
class Child extends Father{...}

子类constructor方法中必须有super,且必须出现在this之前。

1
2
3
4
5
6
7
8
9
10
11
    class Father {
constructor(a){
console.log(a);
}
}
class Child extends Father {
constructor(a){
super(a);
}
}
var child = new Child(2);

es6模块

es6引入了模块化的思想,其设计思想是在编译期间就能确定模块的依赖关系,以及输入和输出的变量。
es6的模块化分为导出export和导入import
每一个模块内的是局部变量,不会污染全局作用域。
每一个模块只加载一次(是单例的),若再去加载同目录下的同文件,直接从内存中读取。
export命令可以出现在模块的任何位置,但必须处于模块顶层。
import命令会提升至整个模块的头部,首先执行,

1
2
3
4
5
6
7
let name = "tom";
let age = 20;
let myFn = function () {
return "222";
}
export {name,age,myFn};
import {name,age,myFn} from "./test.js";

导入和导出

export命令导出的接口名称,须和模块内部的变量有一一对应关系。
导入的变量名,须和导出的接口名称一致,即顺序可以不一致。
import可以改变对象的属性,但不能改变基本类型的值。

1
2
3
4
5
import {a} from "./xxx.js"
a = {}; // error

import {a} from "./xxx.js"
a.foo = "hello"; // a = { foo : 'hello' }

promise对象

是异步编程的一种解决方法。promise是一种状态,从它可以获取异步操作的信息。
有三种状态,pending(进行中),fulfilled(已成功,rejected(已失败).
Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。

async函数

async是es7才有的与异步操作有关的关键字,和promise,generator有很大的关联。
async function name([param[, param[, … param]]]) { statements }
name:函数名称
param:要传递给函数的参数的名称
statements:函数体语句
async函数返回一个promise对象,可以使用then方法添加回调函数。

1
2
3
4
5
6
7
async function helloAsync() {
return "helloAsync";
}
console.log(helloAsync());
helloAsync().then(function (v) {
console.log(v);
})

可以通过then方法打印出来。
async函数中可能会有await表达式,async函数执行时,如果遇到await就会先暂停执行,等到触发的异步动作完成之后,恢复async函数的执行并返回解析值。

1
2
3
4
5
6
7
8
9
10
11
12
13
function testAwait(){
return new Promise((resolve) => {
setTimeout(function(){
console.log("testAwait");
resolve();
}, 1000);
});
}
async function helloAsync() {
await testAwait();
console.log("helloAsync");
}
helloAsync();

await操作符用来等待一个promise对象,只能在异步函数async function内部使用.
返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。

如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function testAwait(){
return new Promise((resolve) => {
setTimeout(function(){
console.log("testAwait");
resolve(222);
}, 1000);
});
}
async function helloAsync() {
var x = await testAwait();
console.log(x);
console.log("helloAsync");
}
helloAsync();

这样会返回一个222给x,打印输出。
await针对所跟不同表达式的处理方式:
promise对象:await会暂停执行,等待promise对象返回resolve,然后恢复async函数的执行并返回解析值。
非promise:直接返回对应的值。

1
2
3
4
5
6
7
function testAwait(){
return ("testAwait");
}
async function helloAsync(){
console.log(await testAwait());
console.log("helloAsync");
}

es6学习(1)

发表于 2019-01-22 | 分类于 js相关

简介

es6主要是为了解决es5的先天不足,例如js里没有类的概念,大多数浏览器支持es6的语法,不过只实现了es6的部分特性和功能。

let和const

let声明的变量只在let命令所在的代码块是有效的,在其余地址无效
const声明一个只读的变量,一旦声明,常量的值便无法修改。

1
2
3
4
5
6
7
{
let a = 0;
console.log(a);
var b = 1;
}
console.log(b);
console.log(a);

a在外部无法打印出,在大括号内部可打印出,b声明的变量是全局有效的。在外部可打印出。
const声明的变量在声明后便无法进行修改。
值得注意的是,const其实保证的不是变量的值不变,而是保证变量指向的内存地址所保存的数据不允许变动。此时,你可能已经想到,简单类型和复合类型保存值的方式是不同的。是的,对于简单类型(数值 number、字符串 string 、布尔值 boolean),值就保存在变量指向的那个内存地址,因此 const 声明的简单类型变量等同于常量。而复杂类型(对象 object,数组 array,函数 function),变量指向的内存地址其实是保存了一个指向实际数据的指针,所以 const 只能保证指针是固定的,至于指针指向的数据结构变不变就无法控制了,所以使用 const 声明复杂类型对象时要慎重。

1
const PI = 3.14

解构赋值

解构赋值是对赋值运算符的扩展。
是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
在代码书写上简洁易读,语义也更加清晰明了。

1
2
let [a,b,c] = [1,2,3];
console.log(b);

可进行忽略的

1
2
let [c,,d] = [1,2,3];
console.log(d);

剩余运算符

1
2
3
≈
console.log(a);
console.log(b);

将1赋值给a,剩余的全都赋值给b
对象模型的解构(object)

1
2
3
let{foo,bar} = {foo:'aaa',bar:'bbb'};
console.log(foo);
console.log(bar);

必须让对应的key对应上,否则将不会对应上。解构。
可嵌套可忽略

1
2
3
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { y }] } = obj;
console.log(x);

可进行解析赋值。
剩余运算符

1
2
3
4
let {a,b,...rest} = {a:10,b:20,c:30,d:40};
console.log(a);
console.log(b);
console.log(rest);

将a,b进行赋值,为10和20,剩余的全都赋值给rest

Symbol对象

es5有5种基本数据类型。分别为number,string,null,undefined和boolean,
es6则新增了symbol。
symbol函数栈不能用new命令,因为symbol是原始数据类型,不是对象。可以接受一个字符串作为参数。

1
2
3
let sy = Symbol("kk");
console.log(sy);
console.log(typeof (sy));

输出为Symbol(kk)和类型为symbol.
使用场景 可以作为属性名. 每一个symbol的值都是不相同的。所以symbol作为对象的属性名,可以保证属性不重名。

1
2
3
let syObject = {};
syObject[sy] = "kk";
console.log(syObject);

ES6的map和set

map对象保存键值对,任何值都可以作为一个键或者一个值。
object中的键只能是字符串或者是symbol.但一个map的键可以是任意值。
key是字符串

1
2
3
4
var myMap = new Map();
var keyString = "a string";
myMap.set(keyString,"键是字符串");
console.log(myMap.get(keyString));

key是对象

1
2
3
4
var myMap = new Map();
var keyObj = {};
myMap.set(keyObj,"key是对象");
console.log(myMap.get(keyObj));

key是函数

1
2
3
4
var myMap = new Map();
var keyFunc = function(){};
myMap.set(keyFunc,"key是函数");
console.log(myMap.get(keyFunc));

Map的迭代
for…of 的迭代

1
2
3
4
5
myMap.set(0,"zero");
myMap.set(1,"one");
for(var [key,value] of myMap){
console.log(key + "=" + value);
}

只显示key

1
2
3
for(var key of myMap.keys()){
console.log(key);
}

只显示value

1
2
3
for(var key of myMap.values()){
console.log(key);
}

forEach的遍历

1
2
3
myMap.forEach(function(value,key) {
console.log(key + "=" + value);
});

Set对象
set对象允许你存储任何类型唯一的值,无论是原始值或者是对象引用。

1
2
3
4
5
let mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add("some text");
console.log(mySet);

字符串等的一些操作

es5判断包含字符串,用indexOf的方法。
es6新增了includes(),startWith()方法,但只能返回布尔值,
若要知道具体是第几个位置,还是需要用indeOf或者lastIndexOf

1
2
3
4
5
let str = "apple,banana,orange";
console.log(str.includes("banana"));
console.log(str.startsWith("a"));
let str = "ge,banana,orange";
console.log(str.indexOf("ge"));

数值的操作

浮点数的判断相等往往会出现问题
例如

1
console.log(0.1 + 0.2 === 0.3);

会输出false
Number.EPSILON属性表示1与大于1的最小浮点数之间的差。
测试数值是否在误差范围内。

1
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON);

对象的简单表示

1
2
3
4
5
6
7
//对象的简洁表示法
const age = 12;
const name = "Amy";
const person = {age,name};
//等同于
// const person = {age:age,name:name};
console.log(person);

对象中的方法也可以进行缩写

1
2
3
4
5
const person = {age,name,
sayHi(){
console.log("hello");
}
};

允许用表达式作为属性名字,但是一定要将表达式放在方括号的内部

1
2
3
4
5
const obj = {
["he" + "llo"](){
return "ckq";
}
}

…这个运算符可进行两个对象之间的合并。
但是要注意的是,自定义的属性和拓展运算符对象里面属性相同的时候,自定义的属性在拓展运算符后面,则拓展运算符的会将其覆盖
如果拓展的在后面,则会将前面那个覆盖

如下

1
2
3
4
5
let person = {name:"Amy",age:15};
let someone = {...person,name:'Mike',age:17};
console.log(someone);
let sometwo = {name:"Mike",age:"17",...person};
console.log(sometwo);

第一个输出name:Mkie,age:17,而第二个输出name:Amy,age:15。

创建数组的方法

1
console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]

参数值可为不同的类型

1
console.log(Array.of(1, '2', true)); // [1, '2', true]

Array.from可将对象迭代转化成为数组
mapFn可以进行迭代,对每个元素进行处理,随后放入数组的是处理后的元素。

1
2
3
console.log(Array.from([1, 2, 3], (n) => {
return n * 5;
})); // [5, 10, 15]

thisArg 可选,用于指定map函数执行时候的this对象.

1
2
3
4
5
6
7
8
9
let map = {
do: function (n) {
return n * 7;
}
}
let arrLike = [1,2,3];
console.log(Array.from(arrLike,function (n) {
return this.do(n);
},map));

表示将map对象传入,随后可以将arrLike中的值进行计算返回。

react语法(2)

发表于 2019-01-22 | 分类于 js相关

获取真实的DOM节点

组件并不是真实的DOM,而是存在于内存之中的一种数据结构,是一种虚拟的DOM,只有当插入DOM的时候,才会变成真正的DOM,根据react设计的规则,所有DOM的变动,都先体现在虚拟DOM上,然后再将实际变化的部分,反映到真实的DOM上。可以极大的提高网页的性能。
有时,为了获取真实的DOM节点,这时就要用到ref属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyComponet extends React.Component{
//构造方法
constructor(props){
super(props);
this.myText = React.createRef();
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
this.refs.myText.focus();
}
render(){
return(
<div>
<input type="text" ref="myText"/>
<input type="button" value="关注" onClick={this.handleClick}/>
</div>
)
}
}
ReactDOM.render(
<MyComponet/>,
document.getElementById('example')
)

在以上的代码中,组件myComponet的子组件中有一个文本输入框,用户获取用户的输入,这时就必须获取真实的DOM节点,虚拟的DOM节点是拿不到用户的输入的。所以,文本输入框有一个ref属性,this.refs.[refName]便可以返回这个真实的DOM。
属性获取真实的DOM值,必须等到虚拟DOM插入后,才能使用这个属性,否则就会报错。通过为组件指定click事件的回调函数,确保了只有等到真实的DOM发生click事件之后,才会读取this.refs.[refName]属性。

this.state

组件要与用户发生互动,react的一大创新,就是将组件看成是一个状态机,一开始的话有一个初始状态,随后与用户进行互动,导致状态变化,从而触发重新渲染UI.

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
class LikeButton extends React.Component{
constructor(props) {
super(props);
this.state = {
like: false
};
this.handleClick = this.handleClick.bind(this);
};
handleClick(event){
this.setState({like:!this.state.like});
};
render(){
var text = this.state.like ? "ckq" : "cpp";
return (
<p onClick={this.handleClick}>
{text}

</p>
)
}
}
ReactDOM.render(
<LikeButton/>,
document.getElementById('example')
)

上面的组件LikeButton中,在构造方法中定义了初始的属性like并设置为false,随后为文本p绑定点击事件handleClick,在handleClick中修改state的值,随后text的值会随着like的变化而变化。最后再重新渲染到页面上。
this.props和this.state都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props表示一旦定义,就无法修改的值,而this.state会随着用户的互动而发生变化的属性。

获取表单的值

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
class Input extends React.Component{
constructor(props){
super(props);
this.state = {
value:"hello"
};
this.handleChange = this.handleChange.bind(this);
};
handleChange(event){
this.setState({value:event.target.value});
};
render(){
var value = this.state.value;
return (
<div>
<input type="text" onChange={this.handleChange}/>
<input type="text" value={value}/>
</div>
)
}
};

ReactDOM.render(
<Input/>,
document.getElementById('example')
)

在Input组件中,有两个子组件input,为第一个子组件绑定时间handleChange,可以获取它的值,随后将value设置为当前的值,并且可以在第二个input中动态发生绑定和变化。也就是说第二个input的值会随着第一个input的值的变化而变化。

组件的生命周期

组件的生命周期可以分为3个状态
Mounting:已插入真实DOM。
Updating:正在被重新渲染。
Unmounting:已移出真实DOM。
react为每个状态提供了2中处理函数.will在进入状态之前调用,did在进入状态之后调用。
共计5种处理函数。

此外,react还提供了2种特殊状态的处理函数。

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
class Hello extends React.Component{
constructor(props) {
super(props);
this.state = {
opacity:1.0
}
};
componentWillMount(){
console.log(111);
}
componentDidMount() {
console.log(222);
}

render() {
return (
<div>hello</div>
);
}
}

ReactDOM.render(
<Hello/>,
document.getElementById('example')
)

在组件渲染出来的过程中,先打印出111,随后再打印出222.

计算机网络复习

发表于 2019-01-21 | 分类于 计算机网络

计算机网络概述

计算机网络就是一些互联的,自治的计算机系统的集合。将一个分散的,具有独立功能的计算机系统,通过通信设备和线路连接起来,由功能完善的软件实现资源共享和传递的系统。
计算机网络按照分布范围可分为
广域网(WAN),覆盖范围:几十千米到更大范围
城域网(MAN),覆盖范围:50~100km,
局域网(LAN),覆盖范围:一个实验室或者一幢大楼。
个人局域网(PAN) 覆盖范围:10m左右。
按网络拓扑结构分为:星形网络,总线型网络,环形网络,网状型网络。网状型没有中线点。
计算机网络的性能标准有下面几种:
1.时延带宽积 = 传播时延 × 信道时延
2.时延:是指数据从网络或链路一端到另外一端所需要的时间有以下几种,
发送时延(传输时延):主机或者路由器发送数据帧所需要的时间
传播时延:电磁波在信道中传播一定距离所需要的时间
处理时延:主机或路由器在接收到分组时进行处理所需要的时间
排队时延:分组在进入网络传输时,需经过很多路由器,在进入路由器后要先在输入队列中排队等待处理。
3.吞吐量:单位时间内通过某个网络的数据量
4.信道效率:一个发送周期内,有效地址发送数据所需要的时间占整个发送时间的比率。
5.信道吞吐率 = 信道利用率 × 发送方的发送速率。

计算机网络结构

协议:对等层通信的规则,控制两个对等实体通信 包括3个部分
语义:对构成协议元素的含义的解释,即讲什么。
语法:数据与控制信息的结构或格式,即怎么讲。
同步:规定了事件的执行顺序。

接口:相邻两层交换信息的连接点。从物理层开始,每一层向上一层提供服务访问点,既没有接口就不能提供服务。
服务:下层为紧邻的上层提供的功能调用。
协议是水平的,服务室水平的。
第n层的实体不仅要使用n-1层提供的服务,实现自己这层的功能,也需要向n+1层提供服务。
分层结构的优点:各层之间相对独立,灵活性好,易于抽象和标准化,

OSI参考模型和TCP/IP参考模型

OSI模型由下至上包括物理层,数据链路层,网络层,传输层,应用层,表示层,会话层。 各层传输的基本单元:
物理层:比特 数据链路层:帧 网络层:分组 传输层:报文
物理层位第一层 数据链路层位第二层,由此往上推。
TCP/IP模型由下至上包括网络接口层,网际层,传输层,应用层,网络接口层对应OSI的物理层和数据链路层,网际层对应网络层,传输层对应传输层,应用层对应会话层,表示层,应用层。
两种体系的比较。
相同点:都采用分层的体系结构,都是基于独立的协议栈的概念。都可以解决异构网络的互联。
不同点:

  1. OSI精确定义了服务、协议和接口,而TCP/IP则没有
  2. OSI不偏向任何协议,通用性好,而TCP/IP只适用于TCP/IP的协议栈
  3. TCP/IP考虑到了多种易购网互联问题,并将网际IP作为一个单独的重要层次,而OSI只考虑用一种标准的公用数据将不同的系统互联
  4. OSI在网络层支持无连接和面向连接,在传输层仅支持面向连接,而TCP/IP在网际层仅支持无连接,在传输层支持无连接和面向连接
    OSI定义的非常全面,就是实现难,所以大家都采用TCP/IP.

网络层

IP协议:是一种无连接的,不可靠的分组传送服务的协议。提供的是一种尽力而为的服务。
无连接:意味着IP协议并不维护IP分组发送后的任何状态信息,每个分组的传输过程都是相互独立的。
不可靠:意味着IP协议不能保证每个IP分组能够正确的,不丢失的和顺序的达到目的主机。

IPV4协议概述

数据报首部包含了如下字段:版本,首部长度,总长度,标识,标志,片移位,首部校验和,生存时间(TTL),协议,源地址,目的地址。
首部大小是60B,其中21~60B是可选字段和填充。
此部分要注意片偏移的计算。
1.首部长度单位是4B,总长度单位是1B,片偏移长度是8B
2.标识代表该分片属于哪个分组,标志有3位,最低位MF = 1表示后面还有分片,MF = 0表示最后一个分片,中间位DF = 0 时才允许分片。
3.片偏移指该分片相对于原分组的相对位置。

IPV4地址分类

IPV4分配在一个全世界范围内唯一的32位的标识符,一般将IPV4地址分为A,B,C,D,E,5类。
A类:网络号为前面8位,并且第一位规定为0.网络地址为全0是一个保留地址。为本网络的意思,例如0.0.0.1表示在网络上主机号为1的主机。A类可以指派的网络号为27 - 2
B类:网络号为前面16位,并且前面2位规定为10。
C类:网络号为前面24位,并且前面3位规定为110。

注意地方:
1.主机号全0表示网络地址。
2.主机号全1表示本网络的广播地址。可当做直接广播地址。将一个分组发送到一个特定网络上的所有主机。
保留地址:
A类为10.X.X.X 10.0.0.0 ~ 10.255.255.255 私有地址在互联网上不使用,只被用在局域网络中的地址。127.X.X.X是保留地址,用作循环测试用的。
B类为172.17.0.0 ~ 172.31.255.255是私有地址。
C类为192.168.0.0 ~ 192.168.255.255是私有地址。
地址范围:
A类:1.0.0.0 ~ 127.0.0.0
B类:128.0.0.0 ~ 191.255.255.255
C类:192.0.0.0 ~ 223.255.255.255
子网划分:
划分子网的基本思路:从主机号借用若干个比特位作为子网号,而主机号也就相应减少了几个比特位,网络号不变。
IP地址 = <网络号>,<子网号>,<主机号>
此时便有子网掩码这一概念。A类的子网掩码位255.0.0.0 将子网掩码和IP地址进行与运算便能求出网络号。
CIDR(无类别域间路由)
消除了传统的A类,B类,C类地址以及划分子网的概念
IP地址 = 网络前缀:主机号 例如128.14.32.0/20 表示前面20位为网络前缀。地址主机号是12位。

ARP协议:将IP地址转化为物理地址,即MAC地址的协议。
DHCP协议:动态主机配置协议,提供了即插即用的原则。允许一台计算机加入新的网络和获取IP地址而不用手动配置。
ICMP协议:主机在发送数据报时,经常会由于各种原因而发送错误,如路由拥塞丢弃等,检测出错误的路由器或者主机将一些控制信息告诉发送数据的主机。
发送数据的主机可以根据ICMP报文确定发生错误的类型。分为2种,
ICMP差错报告报文和ICMP查询报文。
差错报告报文有:1.终点不可达 2.源站抑制,3.时间超时,4.参数问题 5.改变路由(重定向)
ICMP询问报文的分类:1.有回送请求和回答报文 2.时间戳请求和回答报文。3.掩码地址请求和回答报文 4.路由器询问和通告报文。
NAT协议:网络地址转换(NAT)是将私有地址转换为公有地址,从而对外部隐藏了内部管理的IP地址。可大大节省IP地址的消耗。

IPV6协议

地址有24个16进制数组成,共128位,常将一个域中连续的0缩写为一个0,当有相继的0值域时,可使用::,来进行进一步的缩写。但这种缩写只能出现一次。例如如下一个典型的IPV6地址:21DA:0000:0000:0000:02AA:000F:FE08:9C5A

路由协议

因特网有两大类路由选择协议:内部网关协议(IGP)和外部网关协议(EGP)
路由信息协议(RIP)是IGP中最先得到应用的,采用距离-向量路由算法,它的主要思想如下:
1.每一个路由器维护他自己到其他每一个网络的距离记录
2.直接相连的网络跳数为1,每经过一个路由器距离加1
3.RIP认为好的路由就是跳数最少的路由,故优先选择跳数少的路由
4.每条路径最多有15个路由器,距离等于16时即代表不可达
5.每三十秒,相邻两个路由器就会把自身所有信息交换一次,以此更新路由信息。显然,当有两个相邻路由器能达到同一目的网络时,本地路由器会选择跳数较小的那一个。这也就导致了RIP中网络故障消息传得慢(快消息传得慢)。
RIP总结如下:
(1)只发给邻居 (2)发自己全部的路由表 (3)定时发送。
好消息传得快,坏消息传的慢
开放最短路径优先协议(OSPF),采用链路状态路由算法,它的主要思想如下:
1.OSPF向本系统中所有路由器发送信息,这里使用洪范法。
2.发送的信息就是本路由器相邻的所有路由器的链路状态,但这只是路由器知道的部分信息。“链路状态”是指本路由器都和哪些路由器相邻,以及该链路的代价
3.现在每个路由器都知道了其他路由器的相邻路由器,建图
4.采用Dijkstra算法。
5.只有链路状态发生变化时,路由器才使用洪范法向所有路由器发送信息,因此不会出现坏消息传得慢的问题。而在RIP中,不管网络拓扑是否变化,路由器之间都会定期交换信息
OSPF总结如下:
(1)发送给全网络的路由器 (2)发自己和邻居的信息 (3)只有链路状态更新了才发送
边界网关协议(BGP)是不同自制系统之间交换路由信息的协议,属于外部网关协议,主要思想如下:
1.每一个自治系统都要选择至少一个路由器作为该自制系统的BGP发言人。
2.两个BGP发言人之间要交换路由信息就必须建立TCP连接,在此基础之上,建立BGP会话。
3.所有BGP发言人都互相交换网络可达性的信息后,各BGP发言人就找到到达各个自制系统较好的路由。

3种路由协议的比较

协议 RIP OSPF BGP
类型 内部 内部 外部
路由算法 距离-向量 链路状态 路径-向量
传递协议 UDP IP TCP
路径选择 条数最少 代价最低 较好,非最佳
交换节点 与本节点相邻的路由器 网络中所有的路由器 与本节点相邻的路由器
交换内容 本路由器知道的所有信息 与本路由器相邻的所有路由器链路状态 首次是整个路由表,之后是变化的部分

传输层

传输层功能

为两台主机提供了应用进程之间的通信,又称为端到端通信,由于网络层协议是不可靠的,会使分组丢失,失序和重复等,所以派出传输层为数据传输提供可靠的服务。
主要功能如下:
1.提供应用进程间的逻辑通信,(网络层提供主机之间的逻辑通信)
2.差错检测。
3.提供无连接或面向连接的服务。
4.复用和分用。
主要有两种协议 TCP协议和UDP协议。
端口是传输层服务访问点,端口是用来表示应用层的进程。
端口号中0~1023称为熟知端口号,1024~49151称为登记端口号,49152~65535称为临时端口号,通信结束后,这些端口号将不复存在。
常用的端口号有:

应用程序 FTP数据连接 FTP控制连接 TELNET SMTP DNS HTTP TFTP SNMP POP3
熟知端口号 20 21 23 25 53 80 69 161 110

套接字 = (主机IP地址,端口号),用于表示和区分一台主机中的不同应用进程。

UDP协议

只在IP的数据报服务上增加端口的功能(为了找到进程)和差错检测的功能。UDP是面向报文的。
UDP首部只有8个字节,包括四个字段:源端口、目的端口、长度、校验和。源端口用于对方回复用,不需要时可以为0。当源主机不需要计算校验和时,令校验和字段为0。
接收方UDP发现收到的目的端口号不正确时,丢弃该报文并由ICMP发送“端口不可达”差错报文给发送方。
UDP校验时要在数据报之前加上12B的伪首部,这个伪首部不向下传送也不向上提交,仅用于计算校验和。UDP校验时把首部和数据部分一起校验
主要特点:
1.传送数据前无需建立连接,数据到达后也无需确认。
2.不可靠交付。
3.报文头部短,传输开销小,时延较短。

TCP协议

TCP是面向字节流的。尽管TCP的交互式一次一个的数据块,但TCP将其仅仅看做一连串无结构的字节流。
TCP报文段首部由20B的固定长度,包括如下字段:源端口号和目的端口号、序号字段、确认号字段、数据偏移、保留字段、确认位ACK、同步位SYN、终止位FIN、窗口字段、校验和。其他还有一些选项、填充字段(目的是使长度为4B的整数倍)。值得注意的地方如下:
1.序号字段表示本报文段发送的数据的第一个字节的序号
2.确认号代表希望下次收到的报文段数据的第一个字节的序号
3.数据偏移指TCP报文段的数据起始处距离TCP报文段的起始处有多远(就是头部的长度)
建立连接需要进行三次握手 如下:

释放连接需要进行四次握手 如下:

需掌握TCP状态机的各种转换
TCP的流量控制
通过滑动窗口机制来实现发送方和接收方的收发平衡,避免发送方发的太快,接收方来不及接收。
TCP拥塞控制:
在某段时间内,若对网络中某种资源的需求超过了该资源所能提供的可用部分,网络的性能将会变坏-产生拥塞。出现资源拥塞的条件是对资源需求的总和 > 可用资源。
有以下几种算法。
慢开始算法:初始拥塞窗口(cwad)=1,每次收到一个新的报文段确认后,将cwad加1。注意每次收到一个确认后,cwad只会增加1,但是宏观来说,经过一个RTT后,cwad就会变为2倍,也就是2,4,8的增长。
拥塞避免算法:当cwnd达到慢开始门限ssthresh后就开始使用拥塞避免算法。此时每经过一个RTT就让cwad加1。注意当cwad * 2>ssthresh时,下一个cwad应等于ssthresh
网络拥塞处理:每出现一次超时,就让ssthresh等于当前的cwad的一半,然后把cwad置为1,然后执行慢开始算法
快重传:首先要求接收方每收到一个失序的报文段后就立即发出重复确认,这样做可以让发送方及早知道有报文段没有到达接收方,发送方只要连续收到3个重复确认就应当立即重传对方尚未收到的报文段。
快恢复:发送发连续收到三个重复的冗余ACK报文时,就让ssthresh等于当前的cwad的一半,然后把cwad设置为ssthresh改变后的值,然后执行拥塞避免算法 。
**发送窗口实际大小 = min(接收窗口(rwad),拥塞窗口(cwad))
运行过程如下所示:

疑问

为何建立连接需要3次握手:为了防止失效的连接请求报文段突然又传送到主机B ,因而产生错误。
失效的连接请求报文指的是:主机A发送的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新想主机B发送连接请求,且建立成功,顺序完成数据传输。考虑一种特殊的情况,主机A第一次发送的连接请求没有丢失,而是因为网络节点导致延迟到达主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直在等待主机A发送数据,导致主机B的资源浪费。

应用层

域名系统(DNS)

DNS系统将域名转化为IP地址或把IP地址转换为域名,采用客户/服务器模型,运行于UDP之上,使用53号端口
域名服务器包括根域名服务器、顶级域名服务器、授权域名服务器和本地域名服务器
域名解析过程包括递归式和非递归式。但不管怎么样,查询顺序总是:本地域名服务器->根域名服务器->顶级域名服务器->权限域名服务器,且总由本地域名服务器将结果返还给主机
迭代查询:根域名服务器收到请求后,要么给出所要查询的IP地址,要么告诉本地域名服务器下一步应当向哪一个域名服务器进行查询,然后让本地域名服务器进行后续的查询。 如下:

递归查询:指本地域名服务器只向根域名服务器查询一次,后面的几次查询都是在其他几个域名服务器之间进行的。

域名分为顶级域名 国家顶级域名.uk 通用顶级域名.com .net 基础域名服务器
四级域名.三级域名.二级域名.顶级域名

文件传输协议(FTP)

FTP用于文件传送,采用客户/服务器模型,通过两个并行的TCP连接
控制连接:端口21,用于传送FTP控制命令,如连接请求、传送请求、终止请求。他在整个会话期间保持打开状态,在传输文件时也可以使用控制连接。FTP的控制信息也可以称是“带外传送”
数据连接:端口20,用于数据传输

电子邮件(E-mail)

SMTP采用C/S模型,建立在TCP连接上,负责把邮件从用户代理推到服务器,或把邮件从一个服务器推到另一个服务器
POP3采用C/S模型,建立在TCP连接上,负责把邮件从邮件服务器拉到用户代理 接收方使用POP3将邮件从邮件服务器中取出。
由于SMTP只能传送一定长度的ASCII码,故需要使用MIME将非ASCII码和ASCII码之间进行翻译

万维网(www)

WWW是一个资料空间,在这个空间中所有资源都通过唯一的“统一资源定位符(URL)”进行标识
超文本传输协议(HTTP)定义了浏览器怎样向万维网请求万维网文档,以及服务器怎样把文档传送给浏览器。
HTTP是无状态的,同一个客户第二次访问同一个服务器上的页面时,服务器并不会记得这个客户。因此可以使用Cookie加数据库的方式来跟踪用户活动
HTTP本身是无连接的,虽然他使用TCP连接保证可靠性,但通信双方在交换HTTP报文之前不用建立HTTP连接
HTTP可使用非持久连接和持久连接。使用非持久连接时,每个网页元素的传输都要单独建立一个TCP连接。使用持久连接时,万维网服务器在发送响应后仍然保持这条连接,使同一个客户和服务器可以继续在这条连接上传送后续的HTTP请求和响应报文
持久连接又分为非流水线和流水线两种方式。对于非流水线,客户在收到前一个响应后才能发出下一个请求。而在流水线方式下,客户每遇到一个对象引用就立即发出一个请求,那么假如请求和相应都是连续发出的,那么所有引用到的对象共计1个RTT延时
HTTP报文是面向文本的,分为请求报文和响应报文
点击查看参考博客
点击查看b站课程
tcp状态机
tcp协议解析

react语法(1)

发表于 2019-01-16 | 分类于 js相关

react网页模板如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
// ** Our code goes here! **
</script>
</body>
</html>

上面代码有两个地方需要注意,最后一个script标签的type为text/babel属性,这是因为react独有的jsx的语法,跟js不兼容,凡是使用jsx的地方,都要加上 type=”text/babel” 。
其次。共调用了3个库,react.js,react-dom.js 和 Browser.js,必须首先加载,react.js是react的核心库,react-dom.js提供与dom相关的操作,browser.js的作用是将jsx的语法转化成js语法。

reactDOM.render作用。

reactDOM.render是react的最基本使用方法。将模板转化为HTML语言。并插入指定的 DOM 节点。如下:

1
2
3
4
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);

运行结果如下:
>

JSX语法

HTML的语言直接写在js中,不加任何引号,这就是jsx的语法,允许html和js相互混合着写。

1
2
3
4
5
6
7
8
9
10
11
12
var names = ['Alice', 'Emily', 'Kate'];

ReactDOM.render(
<div>
{
names.map(function (name, index) {
return <div key={index}>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);

JSX语法的基本规则,遇到html标签<开头,就以html的规则解析,遇到代码块{开头,就以js规则解析。
JSX允许在模板总插入js变量,如果这个变量是一个数组,则会展开这个数组中的所有成员。

1
2
3
4
5
6
7
  var arr = [
<h1>hello</h1>
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
)

组件

react中最重要的部分便是组件,像普通插入html标签一样,在网页中插入这个组件。react.createClass方法用于生成一个组件类。
现在采用了es6的语法,继承react的Component类,创建一个新类。即新组件,随后使用这个组件。name属性由父组件传进,子组件可使用。

1
2
3
4
5
6
7
8
9
 class HelloMessage extends React.Component{
render(){
return <div>hello {this.props.name}</div>
}
}
ReactDOM.render(
<HelloMessage name = "ckq"/>,
document.getElementById('example')
);

需要注意的是,组件类的第一个字母必须大写,否则会报错,例如helloMessage便会报错。另外组件类中只能包含一个顶层标签,否则也会报错。此时这种情况可以在顶部加一个div将其余的元素包裹在其中即可。
组件的属性可以在组件类的this.props对象上获取,比如name属性就可以从this.props.name上读取。

this.props.children

this.props对象的属性与组件的属性一一对应,但是有一个是例外的,就是this.props.children属性,它表示组件所有的子组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class NoteList extends React.Component{
render(){
return (
<ol>
{
React.Children.map(this.props.children,function (child) {
return <li>{child}</li>
})
}
</ol>
)
}
}
ReactDOM.render(
<NoteList>
<span>ckq</span>
<span>cpp</span>
</NoteList>,
document.getElementById('example')
)

上面代码的notelist组件有两个span子节点,它们可以通过this.props.children读取。
this.props.children的值有3中可能,如果当前没有子节点,就是undefined,如果有一个子节点,数据类型就是object,如果有多个子节点,就是array. react中的react.children来处理this.props.children,可以用react.children.map来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。

PropTypes

组件的属性可以接受任意值,字符串,对象,函数等等都可以,有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
需要增加引入prop-types.js文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var data = 123;
class MyTitle extends React.Component{
static propTypes = {
title: PropTypes.string.isRequired,
}

render() {
return (
<div>
{this.props.title}
</div>
);
}
};
ReactDOM.render(
<MyTitle title={data}/>,
document.getElementById('example')
)

上面代码表示,myTitle组件有一个title属性,propTypes告诉react,这个title属性是必须的,而且它的值必须是字符串,我们传过去的title是一个数值,这样,就会报错。

Markdown语法

发表于 2019-01-12 | 分类于 html相关

markdown语法的使用

一级标题

二级标题

三级标题

无序列表

  • 1
  • 2
  • 3

有序列表

  1. 1
  2. 2
  3. 3

    区块引用

  • 不以结婚为目的的 都叫耍流氓

    这是毛主席说的

    二级引用

  • 不以结婚为目的的 都叫耍流氓

    这是毛主席说的

创建新页面

1
$ hexo new "My New Post"

生成静态文件

1
$ hexo g

远程git部署

1
$ hexo d

分割线


超链接 行内式

妙语连珠啥意思
标签与分类生成
标签与分类生成
github hexo搭建
next使用文档
hexo文档
hexo常用命令
markdown语法参考
markdown语法参考
markdown语法参考
markdown语法参考

图片

代码框

1
<p>ckq</p>

表格的书写

学号 姓名 分数
小明 男 75
小红 女 79

表格

字段 说明 备注
authtoken 曹凯强
name 擦擦擦
1…56
KevinSwift

KevinSwift

58 日志
28 分类
64 标签
© 2020 KevinSwift
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4