Spring Cloud

Spring官方在spring boot的基础上,提供了一个名为Spring Cloud的开源项目,它是对Netflix开源组件进一步封装的一套云应用开发工具,一个非常优秀的服务治理框架。另一个非常优秀的服务治理框架 Dubbo。

Netflix公司和Pivotal公司

Netflix是一家视频网站,该网站上的美剧应该是最火的。Netflix的微服务大规模的应用,在技术上毫无保留的把一整套微服务架构核心技术栈开源了出来,叫做Netflix OSS。Pivotal在Netflix开源的一整套核心技术产品线的同时,做了一系列的封装,就变成了Spring Cloud。Spring Cloud到现在为止不只有Netflix提供的方案可以集成,但Netflix是最成熟的。
Pivotal公司:Spring以及衍生框架、做缓存Redis、消息队列框架RabbitMQ、还有更牛的Greenplum,这些都是Pivotal公司的。还有Tomcat、Groovy里的一些顶级开发者,DevOps理论的提出者都在这个公司。Pivotal的Gemfire技术来解决尖峰高流量并发问题,才让12306刷票体验明显提升。

Spring Cloud微服务架构

在Spring Cloud微服务系统中,一种常见的负载均衡方式是:客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在git仓库,方便开发人员随时改配置。

Spring Cloud微服务架构中的几个基础服务治理组件:

  • 服务注册中心:Eureka Server
  • 注册服务:Eureka Client
  • 发现服务:Discovery Client
  • 负载均衡:Load Balance、RestTemplate、Ribbon,Feign
  • 断路器:Hystrix,另外Feign自带断路器功能,断路打开后,可以避免连锁故障,fallback方法可以直接返回一个固定值。
    路由网关转发和过滤器:zuul,zuul还能过滤做一些安全验证,zuul默认和Ribbon结合实现了负载均衡的功能。Zuul是Netflix 提供的一个开源组件,致力于在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。
  • 分布式配置中心:spring cloud config,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。两个角色,config server config client。
  • 消息总线(Spring Cloud Bus):将分布式节点加入消息总线,利用轻量的消息代理(message broker 经纪人)使得应用程序可以高效地解耦通信过程。在众多的开源消息中间件产品中,当前版本的spring cloud bus仅支持两款中间件产品:rabbitmq和kafka两个binder,也可以自己写binder扩展。
  • Api gateway:
    微服务场景下,将细粒度的服务组合起来提供一个粗粒度的服务,所有请求都导入一个统一的入口,那么整个服务只需要暴露一个api,对外屏蔽了服务端的实现细节,也减少了客户端与服务器的网络调用次数。与业务关系并不大的通用处理逻辑可以从api gateway中剥离出来,api gateway仅仅负责服务的编排与结果的组装。这样对一些后端微服务进行了代理,避免了各个后端服务独立管理CORS和验证问题。
  • zuul静态路由配置规则:
    分布式系统中未使用注册服务时,service1的名称可更换,下面的配置中.path中的**会被添加到.url的后面。若不配置.url,可直接使用service1作为请求路径。

    zuul.routes.service1.url=http://localhost:8002/storage/
    zuul.routes.service1.path=/proxy/**
    
  • 动态路由
    动态路由需要达到可持久化配置和动态刷新的效果。即不仅要能满足从spring的配置文件properties加载路由信息,还需要从数据库加载配置。另外一点是,在容器启动后,能动态刷新内存中的路由信息,达到不停机维护路由信息的效果。

Cloud与微服务的关系

微服务是一种架构的理念,提出了微服务的设计原则,从理论为具体的技术落地提供了指导思想。
Spring Boot是一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务。Spring Cloud是一个基于Spring Boot实现的服务治理工具包。Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架。Spring Boot/Cloud是微服务实践的最佳落地方案。

版本变化

  • Spring Cloud Finchley 在2018年 06 月 19 日正式发布,这次的重大发布主要带来了以下 4 项重大更新。
    (1)新增 Spring Cloud Gateway 组件
    Spring Cloud Gateway 是一个基于 Spring Webflux 和响应式 Netty 的下一代 API 网关,用来替换 Spring Cloud Netflix Zuul。它提供了更加简单的动态路由,以及针对每个路由的过滤器(如地址重写、断路器、添加/删除请求头、限流和安全等)。
    (2)新增 Spring Cloud Function 组件
    Spring Cloud Function 的主要功能如下:
    通过一系列函数推进业务逻辑的实现;
    将业务逻辑的开发生命周期从任何特定运行目标中分离,以便相同的代码可以作为一个 Web 端点、一个流处理器或一个任务来运行;
    支持一个跨 serverless providers 的统一编程模型,并拥有独立运行的能力(本地或 PaaS 平台);
    支持在 serverless providers 上面启用 Spring Boot 特性,如自动配置、依赖注入、指标等;
    (3)兼容 Spring Boot 2.0.x
    Finchley 版本是基于 Spring Boot 2.0.x 构建的,官方建议不要与 Spring Boot 1.5.x 及之前的版本一起工作。
    (4)最低支持 JDK 1.8
    JDK 门槛提高了,1.8 毕竟是现在的主流。
  • Camden。
  • Dalston将于 2018 年 12 月结束生命周期。
  • Edgware伴随着 Spring Boot 1.5.x 的结束而结束生命周期。

参考:
《Spring Cloud微服务实战》
http://blog.didispace.com/
http://blog.csdn.net/forezp/article/details/70148833
http://blog.csdn.net/u010066934/article/details/54232622

Spring Cloud 文档
http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_features

PiggyMetrics微服务编译运行解析
http://blog.csdn.net/nihaomanihao11/article/details/73822681
http://blog.csdn.net/rickiyeat/article/details/60792925

中小型互联网公司微服务实践-经验和教训
http://www.ityouknow.com/springcloud/2017/10/19/micro-service-practice.html

Mysql

mysql索引类型

btree索引:mysql中普遍使用B+Tree索引,但在实现方式上又分为聚簇索引和非聚簇索引。
hash索引:

聚簇索引和非聚簇索引

聚簇索引是指主索引文件和数据文件为同一份文件,聚簇索引主要用在Innodb存储引擎中。在该索引实现方式中B+Tree的叶子节点上的data就是数据本身,key为主键。
非聚簇索引是指B+Tree的叶子节点上的data并不是数据本身,而是数据存放的地址。主索引和辅助索引没啥区别,只是主索引中的key一定得是唯一的。主要用在MyISAM存储引擎中。非聚簇索引比聚簇索引多了一次读取数据的IO操作,所以查找性能上会差。

mysql表类型

1.InnoDB:
InnoDB,支持外键、行锁、事务是他的最大特点。如果有大量的update和insert,建议使用InnoDB,特别是针对多个并发和QPS较高的情况。

支持事务,InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务自动提交,这样会影响速度,所以最好是把多条SQL语句显示放在begin和commit之间,组成一个事务去提交。
不加锁读取
支持外键
支持行锁
不支持FULLTEXT类型的索引
DELETE 表时,是一行一行的删除
InnoDB 把数据和索引存放在表空间里面
跨平台可直接拷贝使用
InnoDB中必须包含AUTO_INCREMENT类型字段的索引
表格很难被压缩
InnoDB的主键范围更大,最大是MyISAM的2倍
innodb属于索引组织表,有两种存储方式,共享表空间存储和多表空间存储,两种存储方式的表结构和myisam一样,以表名开头,扩展名是.frm。如果使用共享表空间,那么所有表的数据文件和索引文件都保存在一个表空间里,一个表空间可以有多个文件,通过innodb_data_file_path和innodb_data_home_dir参数设置共享表空间的位置和名字,一般共享表空间的名字叫ibdata1-n。如果使用多表空间,那么每个表都有一个表空间文件用于存储每个表的数据和索引,文件名以表名开头,以.ibd为扩展名。

2.MyISAM:
MyISAM:是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,不支持外键。如果执行大量的select,MyISAM比较适合。

不支持事务,回滚将造成不完全回滚,不具有原子性。
不支持外键
只支持表级锁,不支持行锁定,这样同一个表上的读锁和写锁是互斥的,MyISAM并发读写时如果等待队列中既有读请求又有写请求,默认写请求的优先级高,即使读请求先到,所以MyISAM不适合于有大量查询和修改并存的情况,那样查询进程会长时间阻塞。因为MyISAM是锁表,所以某项读操作比较耗时会使其他写进程饿死。在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。

支持全文搜索,全文索引是指对char、varchar和text中的每个词(停用词除外)建立倒排序索引。MyISAM的全文索引其实没啥用,因为它不支持中文分词,必须由使用者分词后加入空格再写到数据表里,而且少于4个汉字的词会和停用词一样被忽略掉。
DELETE 表时,先drop表,然后重建表
MyISAM 表被存放在三个文件:frm 文件存放表格定义,数据文件是MYD (MYData) ,索引文件是MYI (MYIndex)引伸。
跨平台很难直接拷贝
MyISAM中可以使AUTO_INCREMENT类型字段建立联合索引
表格可以被压缩。
MyISAM支持GIS数据,InnoDB不支持。GIS数据是指空间数据对象:Point,Line,Polygon,Surface等。
MyISAM保存表的具体行数,在查询不带where时,直接返回保存的行数。所以没有where的count(*)使用MyISAM要比InnoDB快得多。因为MyISAM内置了一个计数器,count(*)时它直接从计数器中读;而InnoDB必须扫描全表。所以在InnoDB上执行count(*)时一般要伴随where,且where中要包含主键以外的索引列。这里特别强调“主键以外”,是因为InnoDB中primary index是和raw data存放在一起的,而secondary index则是单独存放,然后有个指针指向primary key。所以只是count(*)的话使用secondary index扫描更快,而primary key则主要在扫描索引同时要返回raw data时的作用较大。

3.对比选择:
MyISAM相对简单,在效率上要优于InnoDB。从效率上来看,如果系统读多写少,对原子性要求低,那么MyISAM最好的选择,且MyISAM恢复速度快,可直接用备份覆盖恢复。如果系统读少写多,尤其是高并发写入,InnoDB就是首选了。

MyISAM与InnoDB两者之间区别与选择,详细总结,性能对比
https://www.cnblogs.com/y-rong/p/8110596.html

Mysql语句调优

1.使用内置缓存
大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次,这些查询结果会被缓存。
对于像 NOW() 、RAND()、CURDATE()等SQL函数都不会开启查询缓存,因为这些函数的返回是会不定的易变的。所以需要用一个变量来代替MySQL的函数,从而开启缓存。

2.使用 EXPLAIN 执行SELECT查询
使用 EXPLAIN 关键字可以打印出MySQL是如何处理SQL语句的,可以帮助分析查询语句或者表结构的性能瓶颈。
EXPLAIN 的查询结果还会告诉索引主键是被如何利用的、数据表是如何被搜索和排序的等等。
在SELECT语句(推荐挑选那个最复杂的,有多表联接的),把关键字EXPLAIN加到前面,可以使用phpmyadmin来执行。然后会看到一张表格。

3. 追加 LIMIT 1
查询表有时已经知道结果只会有一条结果,此时加上 LIMIT 1 可以增加性能。MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据。
但是在用explain查询分析,显示limit 1加与不加,性能相同。是因为可能是使用了缓存吗?

4. 搜索字段建索引
索引并不一定是给主键或是唯一的字段,如果表中有某个字段经常用来做搜索,那么请为其建立索引。
有些搜索是不能使用正常的索引的。例如需要在一篇大的文章中搜索一个词时,如: “WHERE post_content LIKE ‘%apple%’”,索引是没有意义的。这可能需要使用MySQL全文索引或是自己做一个索引(比如搜索关键词、标签)。

5.使用 ENUM 代替 VARCHAR
ENUM 类型是非常快和紧凑的,实际上其保存的是 TINYINT,但其外表上显示为字符串。用这个字段类型来做选项列表变得相当的完美。比如“性别”,“国家”,“民族”,“状态”或“部门”字段,这些字段的取值是有限而且固定的,那么应该使用 ENUM 而不是 VARCHAR。

6.PROCEDURE ANALYSE() 结构建设
PROCEDURE ANALYSE() 会让 MySQL 帮助分析字段和其实际的数据,给出一些有用的建议。只有表中有实际的数据这些建议才会变得有用,因为要做一些大的决定是需要有数据作为基础的。
例如,如果你创建了一个 INT 字段作为你的主键,然而并没有太多的数据,那么,PROCEDURE ANALYSE()会建议你把这个字段的类型改成 MEDIUMINT 。或是你使用了一个 VARCHAR 字段,因为数据不多,你可能会得到一个让你把它改成 ENUM 的建议。但这些建议可能因为数据不够多而决策做得就不够准确。
在phpmyadmin里,你可以在查看表结构时,点击 “Propose table structure” 或“规则表结构”来查看这些建议,建议结果呈现在Optimal_fieldtype字段中。

7.字段尽量设置默认值
除非有特殊原因使用 NULL 值,否则应该总是让字段保持 NOT NULL。NULL需要额外的空间,并且在进行比较的时候,程序会更复杂。
下面摘自MySQL自己的文档:
“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”

MySQL 性能优化…经验分享
https://www.cnblogs.com/pengyunjing/p/6591660.html

sql优化

计算机存储空间分为:寄存器、高速缓存、内存、交换区(外部存储虚拟化)、硬盘以及其他的外部存储。从寄存器开始到硬盘读写速度是从快到慢依次递减。对于批量记录如果一条一条的连接数据库进行操作,耗费的时间非常恐怖。调优的环节之一,则是减少与数据库交互的次数,将多条查询、插入、更新合并为交互一次,也就是批操作。多次处理的操作交给主程序在内存中进行处理,内存中处理的速度要快上很多。

批量插入语句
将插入语句进行拼接,多条插入语句拼接成一条插入语句,与数据库交互一次执行一次。

//如果字符串太长,则需要配置下MYSQL,在mysql 命令行中运行 :
set global max_allowed_packet=2*1024*1024*10
//批量插入语句
insert into 表名(字段名1,字段名2)values(值a1,值b1), (值a2,值b2)

批量更新语句

UPDATE categories SET 
display_order = CASE id 
        WHEN 1 THEN 3 
        WHEN 2 THEN 4 
        WHEN 3 THEN 5 
END, 
title = CASE id 
        WHEN 1 THEN 'New Title 1'
        WHEN 2 THEN 'New Title 2'
        WHEN 3 THEN 'New Title 3'
END
WHERE id IN (1,2,3);

批量查询和删除

select * from tableName where id in (1,2,3,4) order by id
delete from tableName where id in(1,2,3,4,5,6)

LoopBack

ES6的出品为JS成为企业级语言扫清障碍,与之配套的需要一个真正的企业级框架。Express是一个精巧的微内核不足以支撑起一个大项目。
LoopBack 是建立在 Express 基础上的企业级 Node.js 框架,这个框架有以下特点:

  • 编写少量代码就能创建动态端到端的 REST API
  • 支持主流的数据源,例如 Mongodb、MySQL、SOAP 等和 REST API 的数据。
  • 一致化的模型关系和对 API 访问的权限控制
  • 可使用内置的用于移动应用场景下的地理定位、文件服务以及消息推送
  • 提供 Android、iOS 和 JavaScript 的 客户端SDK

LoopBack 作为一个面向企业级的 Web 框架,提供了更丰富的功能,方便添加模型,权限控制,连接数据源等操作。例如可以通过修改配置增加模型,并指定模型的数据源。它默认提供了一些基础模型,例如 User 这个模型包含了注册登录等逻辑,可以非常方便的继承这些内建模型,实现个性化的定制。它还提供了 Hook 编程的机制,提供了可视化的调试页面,自动生成对应的前端 SDK 。这些功能在开发大型 Web 服务的时候,帮助我们更容易查看和管理项目。

StrongLoop 是 IBM 的一家子公司,StrongLoop 的 LoopBack 框架能够轻松地连接数据并将数据公开为 REST 服务。它能够在图形(或命令行)界面中以可视方式创建数据模型,可以使用这些模型自动生成 REST API – 从而为 REST 服务层生成 CRUD 操作,无需编写任何代码。这很重要?因为它使 API 开发变得更容易,并显著减少了从概念到实现所需的时间。

在 LoopBack 框架中,是通过所谓的“数据连接器”来获取和持久化数据。

Cloudant 是一个 DBaaS 服务,是一个衍生的 Apache CouchDB,所以将 LoopBack 连接器连接到 Cloudant 很简单,只需在应用程序中使用现有的社区驱动的 CouchDB LoopBack Connector。

StrongLoop 是生成 LoopBack 框架的工具程序,有的认为Strongloop 相当于Loopback + Angularjs。

相关文章

node 框架 LoopBack 教程
https://cnodejs.org/topic/57e5b2859c495dce044f397c
StrongLoop学习笔记(一)
https://blog.csdn.net/sanpo/article/details/45082089
使用Loopback3.0构建应用程序(一)
https://www.jianshu.com/p/763b1a847d2c
IBM developerWorks,可以其中搜索Strongloop
https://www.ibm.com/developerworks/cn/
Loopback 2.0
http://loopback.io/doc/en/lb2/Remote-methods.html#overview
Loopback 3.8.0
http://apidocs.strongloop.com/loopback/#model-remotemethod
http://apidocs.strongloop.com/loopback/#persistedmodel-create
https://loopback.io/doc/en/lb3/Remote-methods.html
find方法中Filter的where中的语法格式:
http://loopback.io/doc/en/lb2/Where-filter.html#where-clause-for-queries

使用loopback做邮箱验证,LoopBack用户模型提供了注册新用户并确认其电子邮件地址的方法。您还可以使用loopback-component-passport模块将登录信息与Facebook,Google和其他第三方提供商集成。
https://www.jianshu.com/p/21b4d84fb7af

生成lb-services.js

Loopback生成lb-services.js,使用Loopback CLI工具的lb-ng命令

$ lb-ng server.js lbservices/lb-services.js

代码示例

//自定义方法
Unit.remoteMethod(
        'deleteRecursive',
        {
            description:'',
            accessType: 'WRITE',
            accepts: {arg: 'id', type: 'string',description: '机组 id', http: {source: 'query'}},
            returns: [{arg: 'status', type: 'string'}],
            http: [
                {verb: 'delete', path: '/deleteRecursive'}
            ]
        }
    );
#source的选择有 body,path,query
//实现包装find的功能
    Project.findProjects=function(filter,callback) {
        console.log("findProjects",filter);
        var json=JSON.parse(filter);
        Project.find(json,function (err,data) {
            callback(null,data);
        });
    }
    Project.remoteMethod('findProjects', {
            description:'查询工程列表',
            accessType: 'READ',
            accepts: {arg: 'filter', type: 'string',description: '查询条件', http: {source: 'query'}},
            returns: {type: 'array', root: true},
            http: [
                {verb: 'get', path: '/findProjects'}
            ]
        }
    );

ES6

ECMAScript 6.0(简称 ES6)是 JavaScript 语言的下一代标准,在 2015 年 6 月正式发布。它的目标是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
ECMAScript 和 JavaScript 的关系,大体上前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。在日常场合这两个词是可以互换的。

从软件工程角度来看,ES6就相当于当年的Java5,是历史性的发展,从此可以用js做大型项目了。事实上各大主流浏览器现在已经支持大部分新特性了,后端的Node.js更是可以直接使用ES6的绝大多数语法。

Babel

Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在现有环境执行。这意味着可以用 ES6 的方式编写程序,又不用担心现有环境是否支持。

// 转码前,箭头函数
input.map(item => item + 1);

// 转码后,普通函数
input.map(function (item) {
  return item + 1;
});

变量声明方式 let/const

ES6中全面使用let/const替换var。使用let声明一个值会被改变的变量,使用const声明一个值不会被改变的变量,即常量。

与var不同,新的变量声明方式带来了一些不一样的特性,其中最重要的两个特性就是提供了块级作用域与不再具备变量提升。let或const变量一定要在声明后面使用,否则报错is not defined。在实际使用中,尽量避免使用变量提升的特性带来的负面影响。只有在面试题中,才会对变量提升不停的滥用。
var声明的变量仍旧是函数级作用域。

var和let在for循环中的应用:
下面的代码如果使用var,最后输出的是10。

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10
上面代码中最后一行输出的结果是10。变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。

如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。
var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。

既然使用let使的每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
结果:
// abc
// abc
// abc

箭头函数

当函数直接被return时,可以省略函数体的括号。

// es5
var fn = function(a, b) {
    return a + b;
}
// es6 6
const fn = (a, b) => a + b;

箭头函数可以替换函数表达式,但是不能替换函数声明。
箭头函数中没有this。在ES6中,默认采用严格模式,this不会自动指向window对象了,this就只能是undefined。

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。在其中使用 ${} 来包裹一个变量或者一个表达式。

const a = 20;
const b = 30;
const str = `${a}+${b}=${a+b}`;

解构赋值

获取对象属性值都可以使用解析结构来减少代码量。本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量的值就等于undefined。

const props = {
    className: 'tiger-button',
    loading: false,
    clicked: true
}
//取对象中的值到变量
const { loading, clicked } = props;

//数组以序列号一一对应,这是一个有序的对应关系。
const arr = [1, 2, 3];
const [a, b, c] = arr;
let [a, b, c] = [1, 2, 3];

如果变量名与属性名不一致,必须使用完整写法。也就是说,对象的解构赋值的内部机制是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。

遍历 Map 结构:

任何部署了 Iterator 接口的对象,都可以用for…of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

// 只获取键名
for (let [key] of map) {
  // ...
}
// 只获取键值
for (let [,value] of map) {
  // ...
}

默认值

变量默认值

const { loading = false, clicked } = props;

函数参数默认值
在实际开发中给参数添加适当的默认值,可以让我们对函数的参数类型有一个直观的认知。

function add(x = 20, y = 30) {
    return x + y;
}

ES6 内部使用严格相等运算符(===),判断只有当参数严格等于undefined,对会取值为默认值。

展开运算符

在ES6中用…来表示展开运算符。展开运算符可以将数组方法或者对象进行展开。

const arr1 = [1, 2, 3];
const arr2 = [...arr1, 10, 20, 30];//arr2 结果变成了[1, 2, 3, 10, 20, 30];
const obj1 = {
  a: 1,
  b: 2, 
  c: 3
}
const obj2 = {
  ...obj1,
  d: 4,
  e: 5,
  f: 6
}// 结果类似于 const obj2 = Object.assign({}, obj1, {d: 4})

展开运算符还可以声明为变量并接收数据

const props = {
  size: 1,
  src: 'xxxx',
  mode: 'si'
}
const { size, ...others } = props;

展开运算符还用在函数的参数中表示函数的不定参。只有放在最后才能作为函数的不定参,否则会报错。

const add = (a, b, ...more) => {
    return more.reduce((m, n) => m + n) + a + b
}
console.log(add(1, 23, 1, 2, 3, 4, 5)) // 39

对象字面量写法

ES6针对对象字面量做了许多简化语法的处理。
当属性名与值的变量名相同时,在对象结构中可以只写属性名。对象中的方法也可以使用字面量写法。

const name = 'Jane';
const age = 20
// es5
var person = {
  name: name,
  age: age,
  getName: function getName() {
    return this.name;
  }
};
// es6
const person = {
  name,
  age,
  getName() { // 只要不使用箭头函数,this就还是我们熟悉的this
    return this.name
  }
}

还可以使用变量作为对象的键。

const field = 'rock';
const heat = '50%';
const music = {
  [field]: heat
}
console.log(music); // Object {rock: "50%"}

class

ES6为创建对象提供了新的语法糖,就是Class语法。

// ES5
// 构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
}
// 原型方法
Person.prototype.getName = function() {
  return this.name
}

// ES6
class Person {
  constructor(name, age) {  // 构造函数
    this.name = name;
    this.age = age;
  }
  getName() {  // 原型方法
    return this.name
  }
}

babel会将ES6的写法编译成利用Object.defineProperty实现的方式,这个方法的具体用处大家可以在《JavaScript高级编程3》中学习了解,包括get,set,等都有详细的说明

除此之外,我们还需要特别注意在实际使用中的几种写法方式的不同,在下面的例子注释中,我说明了他们分别对应的ES5中的含义。

class Person {
constructor(name, age) { // 构造函数
this.name = name;
this.age = age;
}

getName() { // 这种写法表示将方法添加到原型中
return this.name
}

static a = 20; // 等同于 Person.a = 20

c = 20; // 表示在构造函数中添加属性 在构造函数中等同于 this.c = 20

// 箭头函数的写法表示在构造函数中添加方法,在构造函数中等同于this.getAge = function() {}
getAge = () => this.age

}
箭头函数需要注意的仍然是this的指向问题,因为箭头函数this指向不能被改变的特性,因此在react组件中常常利用这个特性来在不同的组件进行传值会更加方便。

继承 extends

只需要一个extends关键字,可以实现继承了,不用像ES5那样去担心构造函数继承和原型继承。

//es6
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  getName() {
    return this.name
  }
}

// Student类继承Person类
class Student extends Person {
  constructor(name, age, gender, classes) {
    super(name, age);
    this.gender = gender;
    this.classes = classes;
  }
  getGender() {
    return this.gender;
  }
}

还需要关注super方法。在继承的构造函数中必须调用一次super方法,它表示构造函数的继承,与ES5中利用call/apply继承构造函数是一样的功能。

// 构造函数中
// es6 ,super还可以直接调用父级的原型方法,如super.getName。
super(name, age);

// es5
Person.call(this);

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
http://www.jianshu.com/p/fe5f173276bd

模块 Modules

1.引入模块

// src/index.js
import test1 from './test'

上面示例中,import表示引入一个模块,test 暂时理解为引入模块的名字。
引入这个动作执行时,test.js中的代码也执行了。如果在test.js中没有对外暴露任何接口,那么test1为一个空对象。
2.对外提供接口
ES6 modules使用export关键字对外提供接口。
export default对包暴露了一个对象。import 后跟的对象就默认是export default暴露的对象。

export default {
    num,
    arr,
    obj,
    foo
}

还可以通过export暴露更多方法与属性。

export const bar = () => {}
export const zcar = 12345;

可以一次引入获得模块暴露的所有接口。

import * as test1 from './test';

上面示例中的 * 表示所有,这是比较常用的通配符,as表示别名,* as test1的意思是将test.js暴露的所有接口组成的对象,命名为test1。
在引入中使用解析结构,下面示例中test1仍然表示为export default暴露的对象,而 { bar, zcar }则表示从整个返回对象中去取得对应的接口。

import test1, { bar, zcar } from './test';

Symbol

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

Symbol 值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

let s = Symbol();

typeof s
// "symbol"

上面代码中,变量s就是一个独一无二的值。typeof运算符的结果,表明变量s是 Symbol 数据类型,而不是字符串之类的其他类型。
注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

Set和Map

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
  console.log(i);
}
// 2 3 5 4

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。

首先,WeakSet 的成员只能是对象,而不能是其他类型的值。
其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键,是一种更完善的 Hash 结构实现。
Map 遍历有一个forEach方法,与数组的forEach方法类似。

map.forEach(function(value, key, map) {
  console.log("Key: %s, Value: %s", key, value);
});

WeakMap结构与Map结构类似,也是用于生成键值对的集合。

Generator 函数

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

前端基础进阶系列
https://www.jianshu.com/p/cd3fee40ef59
ECMAScript 6 入门
http://es6.ruanyifeng.com/

JS基础

字符串和整数混合运算

‘1’+1 结果 ’11’
‘1’-1 结果 0
1+1+’1′ 结果 ’21’
‘1’+1+1 结果 ‘111’

类型转换

1.转Number
数字:转换后还是数字
字符串:如果可以被解析为数值,则为相应的数值,如果不能,则是 NaN,如果是空字符串那就是0
布尔值:true为1,false为0
undefined:NaN
null:0
object:先执行valueOf,看是否能转换,如果不可以再执行toString,看是否可以转换,如果不可以报错
2.转String
数字:转换成对应的字符串
字符串:还是对应的字符串
布尔值:true为’true’,false为’false’
undefined:undefined
null:null
object:先执行toString,看是否能转换,如果不可以再执行valueOf,看是否可以转换,如果不可以报错
3.转Boolean
下面这几个是false,其他都是true
NaN
null
undefined
0
“”
false

4.隐式类型转换
四则运算、判断语句中在隐式类型转换。

逻辑判断

=== 会先判断类型是否相同,再判断内容是否相同
== 只判断内容是否相同
1==’1′ 结果true

逻辑判断

给字符串添加属性并赋值,再打印此属性,值为undefined。这说明并不能给字符串增加属性。

JS基础知识(覆盖JS基础面试题)
https://yq.aliyun.com/articles/608880

Node应用

REPL

REPL(Read Eval Print Loop:交互式解释器)

Node 自带了交互式解释器,可以很好的调试 Javascript 代码,可以执行以下任务:

读取 – 读取用户输入,解析输入了Javascript 数据结构并存储在内存中。
执行 – 执行输入的数据结构
打印 – 输出结果
循环 – 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出。

http://www.runoob.com/nodejs/nodejs-repl.html

集成测试

持续集成

持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作,功能包括:
1、持续的软件版本发布/测试项目。
2、监控外部调用执行的工作。

Jenkins使用极低的代价能部署一个软件,自动化进行项目构建,项目测试,静态扫描,上传构建,远程备份,发布。很多时候只需要点击立即构建,就进行了项目的部署操作。
它还提供权限管理,可以让不同的人员负责各自的项目建构。多项目构建,可以一次性完成多个项目的构建。

官方地址:https://jenkins.io/
docker:https://hub.docker.com/r/jenkins/jenkins/

Jenkins的原理,如果在新建的时候指定了Maven项目和代码的Git地址,Jenkins首先会通过Git将代码clone到本地,然后执行在Build中指定的pom.xml文件和指定的命令。

https://blog.csdn.net/bntX2jSQfEHy7/article/details/78743664

Jenkins 启动一直显示 Jenkins正在启动,请稍后…,深度修改配置中的访问的网站地址。
https://blog.csdn.net/heatdeath/article/details/79733611

对于自动安装失败的插件,可以在错误中找到hpi文件,通过手动下载然后在高级页面中上传插件的方式安装。

配置Publish Over SSH

在“系统设置”中配置“Publish Over SSH”。ssh的配置可使用密码,此时Passphrase中要填写应用服务器root等账号的密码。ssh的配置也可以使用密钥,使jenkins服务器可免密码直接登陆应用服务器。在配置密钥之前要先配置好jenkins服务器和应用服务器的密钥认证。在jenkins服务器上使用ssh-keygen -t rsa命令生成密钥对。在docker部署的jenkins/jenkins:lts中成功生成信息如下:

Your identification has been saved in /var/jenkins_home/.ssh/id_rsa.
Your public key has been saved in /var/jenkins_home/.ssh/id_rsa.pub.

将jenkins服务器的公钥id_rsa.pub中的内容复制到应用服务器/root/.ssh/authorized_keys文件中,在应用服务器上重启ssh服务service sshd restart。
解释两个不大明确的配置项:
Passphrase:生成rsa密钥时的密码。
Path to key:jenkins服务器上私钥文件的路径。
配置完成后可点击“Test Configuration”测试到目标主机的连接,出现”success“则成功连接。
https://www.cnblogs.com/hanxiaohui/p/8796025.html
https://www.jianshu.com/p/0d805ed204e6