为了账号安全,请及时绑定邮箱和手机立即绑定
2.4 百度地图扩展

geo 坐标系需要自行提供地理信息数据,使用上有一定的不便,因此 echarts 提供了另一种地理坐标系实现 —— bmap。bmap 扩展将百度地图带入 echarts,以百度地图为底图绘制地理坐标系,所以使用上就不用再关注地理数据了,而且依托于百度地图提供的强大功能,bmap 在伸缩、移动、精度等方面更出色。使用时,除了 echarts 文件外,还需要引入百度地图依赖、bmap 扩展依赖,以 CDN 为例:<!-- 引入百度地图的jssdk --><!-- 配置方法可参考: http://lbsyun.baidu.com/index.php?title=jspopular3.0 --><script src="//api.map.baidu.com/api?v=2.0&ak="></script><!-- 引入 ECharts --><script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script><!-- 引入 bmap 扩展 --><script src="//cdn.bootcss.com/echarts/4.5.0/extension/bmap.min.js"></script>引入后,就可以通过 bmap 配置地理坐标系。bmap 所支持的配置项比较少,包括:配置名类型默认值说明centerarray当前视图的中心点,用经纬度表示roamboolean|stringfalse是否开启鼠标缩放和平移漫游。zoomnumber1当前视角的初始化缩放比例mapStyleobject旧版地图的自定义样式接口,详见: http://developer.baidu.com/map/jsdevelop-11.htmmapStyleV2object新版地图的自定义样式,详见: http://developer.baidu.com/map/jsdevelop-11.htmbmap 包含了百度地图所支持的所有地理区域信息,所以应用时只需通过 center 指定视图中心点,通过 zoom 控制视图区域,即可实现地理坐标系,示例:1321示例效果:此外,还可以通过 myChart.getModel().getComponent('bmap').getBMap(); 接口获取 bmap 对应的地图实例,实现与地图的交互。在上述示例基础上,添加额外代码:// 获取地图实例var map = myChart.getModel().getComponent('bmap').getBMap();// 添加交通状况层var traffic = new BMap.TrafficLayer();map.addTileLayer(traffic);// 重置视图中心map.centerAndZoom(new BMap.Point(114.48, 38.03), 8);示例效果;完整的开发指南,请参考 百度地图。

2.3 地图布局

地理坐标系中,与地图布局相关的属性较多,包括:配置名类型默认值说明centerarray当前视图的中心点,用经纬度表示zoomnumber当前视图的缩放比例aspectScalenumber0.75地图长宽比boundingCoordsArray二维数组,定义定位的左上角、右下角对应的经纬度layoutCenterarray定义地图中心在屏幕中的位置layoutSizenumber|string定义地图大小leftnumber|string坐标系离容器左侧的距离topnumber|string坐标系离容器上方的距离rightnumber|string坐标系离容器右侧的距离bottomnumber|string坐标系离容器下方的距离widthnumber|string坐标系宽度heightnumber|string坐标系高度其中,left、top、right、bottom、width、height 是 echarts 中通用的定位手段,含义与配置方法都与其他组件一样。下面讨论列表中不太常见的属性。2.3.1 aspectScaleaspectScale 用于控制地图缩放的宽高比例。这个概念并不复杂,使用经纬度定义的地理信息本身带有宽高比例 aspect = width/height,那么渲染时若确定了地理坐标系的宽度为 x,则 y = x * aspect,形如:是不是跟我们平常看到的不一样?这是因为经纬坐标系是建立在地球的三维椭圆体上的,映射到二维平面时会产生一定的形变,所以绘制时需要在经纬度比例基础上加上椭圆形变,在 echarts 上则是通过 y = x * aspect * aspectScale 实现,通常保持默认值 0.75 即可:2.3.2 layoutCenter 与 layoutSizelayoutCenter、layoutSize 提供了另外一种布局方法,它们将地图坐标系调整为最长边等于 layoutSize`的盒子,并将盒子的中心点放置在 layoutCenter 位置上。基于 layoutCenter、layoutSize 的布局能够保持地图高宽比的情况下把地图放在某个盒形区域的正中间,并且保证不超出盒形的范围。使用上请注意:两者必须同时出现才有效;当配置了这两个属性后,left、top、right、bottom、width、height 均失效;layoutCenter、layoutSize 仅设定初始化时的布局效果,坐标系依然可以通过放大、移动变更位置和大小。例如:1319示例效果:2.3.3 center 与 boundingCoordscenter 用于定义当前视图的中心点,以经纬度坐标表示,形如: center: [-80, 30]; boundingCoords 则用于定义当前视图的左上角、右下角经纬度,以二维数组表示,形如:{ boundingCoords: [ // 定位左上角经纬度 [-90, 30], // 定位右下角经纬度 [-120, 50], ],}center 与 boundingCoords 互斥,当同时存在时,优先使用 center。从定义可以看出,center 定义的是地图所展示的中心区域的位置,配合 zoom 属性可以控制视图中展示的地图多寡,例如下例中:1320示例效果:而 boundingCoords 定义是地图坐标系所展现的整个内容区域的经纬度,使用时不需要考虑缩放比例,相对更简单。上例基础上,修改 geo:{ geo: { map: 'USA', roam: true, boundingCoords: [ // 定位左上角经纬度 [-90, 30], // 定位右下角经纬度 [-120, 50], ], },}示例效果:

4.2 引入本地图片

在 css 中引入本地文件(比如图片、字体)也可以使用相对路径和绝对路径。需要注意的是,有些小程序端 css 文件不允许引用本地文件,这些平台包括微信小程序、QQ小程序、字节跳动小程序、App v2。(1)绝对路径实例:<style> /* 引入图片 */ .imooc-banner { background-image: url(/static/logo.png); background-image: url(@/static/logo.png); }</style>

2. IP 地址

IP 地址有 IPv4 和 IPv6 两个版本。IPv4 地址长度是 32 bit,4 个字节,每个字节是独立取值,通常用点分十进制的形式表示。例如,192.168.0.100。IPv4 地址范围是 0.0.0.0 ~ 255.255.255.255,最多包含 4294967296(2^32) 个 IP 地址。而 IPv6 的地址格式是八元组形式,比如 2001:0DB8::1428:57ab。本节只讨论 IPv4 地址。IPv4 地址通常划分成网络 ID和主机 ID两部分。比如:IP 地址分类划分如下:分类起始地址结束地址A0.0.0.0127.255.255.255B128.0.0.0191.255.255.255C192.0.0.0223.225.255.255D224.0.0.0239.255.255.255IP 地址分类划分缺乏灵活性,对于 A 类地址来说,网络 ID 只有 2^7 = 128 个,但是主机 ID 多达 2^24 = 16777216 个,主机 ID 浪费很大。对于 C 类地址来说,网络 ID 可以有 2^21 = 2097152 个,但是主机 ID 只有 2^8 = 256 个,对于有些组织来说主机 ID 不够划分。于是 1993 年出现了 CIDR(Classless Inter-Domain Routing)的编址策略,叫做无类别域间路路由选择。CIDR 编址是一种 IP 地址的压缩表示方式,将 IP 地址分为网络前缀和主机标识两部分,形如 A.B.C.D/L 的表示方式,L 是一个小于 32 的十进制数字,代表网络前缀占用 L 个比特,主机标识占用 32 - L 个比特。比如,200.101.80.0/20 表示网络前缀占用 20 个比特,主机标识占用 12 个比特。在 CIDR 编址方式下,如何通过 IP 地址快速确定网络 ID 呢?是通过子网掩码来确定的。对于形如 A.B.C.D/L 的子网,子网掩码是由 L 个 bit 1 和 32 - L 个 bit 0 组成的二进制数。只要把 A.B.C.D 和子网掩码做一个按位与(&)运算,就可以得到网络 ID。可以说,形如 A.B.C.D/L 的表示,可以唯一确定一个网络 ID,我们通常把 A.B.C.D/L 表示叫做网段。你可以说 A.B.C.D/L 表示了一个网段,网段就是形如 A.B.C.D/L 的表示形式。比如,200.101.80.0/20 网段的子网掩码的二进制形式是 11111111 11111111 11110000 00000000,十进制形式是 255.255.240.0。将 200.101.80.0 和 255.255.240.0 做按位与(&)运算,得到的网络 ID 是 200.101.80.0。那么 IP 地址 200.101.96.1 是 200.101.80.0/20 网段的 IP 吗?我们只需要把 200.101.96.1 和 255.255.240.0 做一个按位与(&)运算,查看结果是否等于 200.101.80.0 即可。采用 CIDR 编码方式优势如下:简单灵活有效利用 IP 地址空间减小路由表规模。比如 200.101.80.0/20 网段中的 IP 地址 200.101.80.100,如果按照分类,属于 C 类地址,网络 ID 占用 24 个 bit,主机 ID 占用 8 个 bit;如果采用 CIDR 方式,网络 ID 占用 20 个 bit,主机 ID 占用 12 个 bit。对于主机较多的网络,极大地提高了 IP 地址的利用率。

ECharts 地图坐标系

移动互联网时代,地理位置信息已经成为许多商业决策的重要参考依据,基于地图的图表需求也随之日益增长。ECharts 提供了一套功能完备的地图坐标体系,配合百度地图能够实现非常丰富的图表效果,下面一起看看吧。

2.1 本地仓库

在我们声明的 MAVEN_HOME 路径下,找到 conf\settings.xml,其中可以看到 Maven 的本地仓库路径配置:从上图我们可以看到,Maven 的默认本地仓库路径是在 ${user.home}/.m2/repository,我们为了方便将其修改为了 D:\repo。

2.2 地图上的缩放

地理坐标系中,与缩放相关的配置项包括:配置名类型默认值说明roamboolean|stringfalse是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 scale 或者 move。设置成 true 为都开启zoomnumber1当前视角的初始化缩放比例scaleLimit.minnumber滚轮缩放所支持的最小值scaleLimit.minnumber滚轮缩放所支持的最大值由于地理信息数据的精度有限,建议根据精度范围设定合理的缩放范围,例如:1317

2.1 直角坐标系散点图

勾画直角坐标系下的散点图,最简情况下需要配置:yAxis、xAxis、series,示例:1368示例效果:效果与 折线图 相似,但散点图比折线图强大的地方在于,它可以通过颜色、大小表达出更多维度的信息。简单方法,可以通过 symbolSize 属性修改点的大小,该属性接受如下值:number: 点的像素大小值;array: 二维数组如 [10, 30],第一个值指定 symbol 宽度;第二个值指定 symbol 高度;function: (value: Array|number, params: Object) => number|Array: 回调函数。在上例基础上,修改 series 配置如下:{ series: [ { data: [ ['Mon', 120, 224], ['Tue', 80, 320], ['Wed', 140, 1288], ['Thu', 192, 64], ['Fri', 140, 228], ['Sat', 180, 248], ['Sun', 178, 240], ], type: 'scatter', symbolSize: function (data) { return Math.sqrt(data[2]); }, }, ],}一是在 data 序列上增加第三个维度;二是增加 symbolSize 配置项,通过函数计算出各节点大小。示例效果:还可以通过散点上不同的颜色,表现多维数据,简单方法可通过 itemStyle.color 配置各节点颜色。在上例基础上,修改 series 配置如下:{ series: [ { data: [ ['Mon', 120, 224], ['Tue', 80, 320], ['Wed', 140, 1288], ['Thu', 192, 64], ['Fri', 140, 228], ['Sat', 180, 248], ['Sun', 178, 240], ], type: 'scatter', itemStyle: { color: function (node) { return `hsla(${node.data[2] % 360}, 100%, 50%, 0.8)`; }, }, }, ],}示例效果:注意,上述示例需要手动计算每个节点的颜色、大小属性,这部分逻辑在散点图内部会有更好的实现,只需配合使用 visualMap 即可,下面会有详细介绍。

HTML5 地理位置

地理定位功能是 HTML5 新增的标准,早期的 HTML 和 JavaScript 没有操控硬件和文件的权限,因为页面交互效果比较简单;但是 HTML5 之后网页已经逐渐应用于各种复杂场景包括移动设备,所以增加了各种与硬件交互的 API 接口,地理位置就是其中之一。

3. 修改监听地址和端口

上面说到要在浏览器中输入 localhost:5000 才能看到运行效果。其中 localhost 代表本地 IP 地址,你也可以把 localhost 改成 127.0.0.1,效果和 localhost 是一样的。那么 5000 代表什么呢?其实 5000 是一个端口号,你可以把端口号理解为是门牌号。我们的电脑会为每一个应用程序划分运行区间,每一个运行区间的标识就是端口号,我们可以通过端口号来访问对应的应用程序,这和你在酒店根据门牌号找到房间是一个道理。默认情况下,Flask 应用程序监听地址 127.0.0.1 和端口 5000。如果你不想让 Flask 程序运行在 5000 端口,也可以通过参数设置可以修改默认的监听地址和端口,比如我们想让 Flask 程序运行在一个比较吉利的端口 8888 上面,可以这样修改代码:from flask import Flaskapp = Flask(__name__)@app.route('/')def hello_world(): return '<b>Hello World</b>'if __name__ == '__main__': app.run(host = '0.0.0.0', port = 8888)设定 app.run 的函数参数 host 为 ‘0.0.0.0’,表示监听每一个可用的网络接口;设定 app.run 的函数参数 port 为 8888,表示监听端口 8888。

3. Lambda 表达式的优点

那么 Lambda 具体有哪些优点呢?更加紧凑的代码: Lambda 表达式可以通过省去冗余代码来减少我们的代码量,增加我们代码的可读性;更好地支持多核处理: Java 8 中通过 Lambda 表达式可以很方便地并行操作大集合,充分发挥多核 CPU 的潜能,并行处理函数如 filter、map 和 reduce;改善我们的集合操作: Java 8 引入 Stream API,可以将大数据处理常用的 map、reduce、filter 这样的基本函数式编程的概念与 Java 集合结合起来。方便我们进行大数据处理。

1. 在线查找示例代码

Android Studio 提供了 Browse Samples 功能,我们可以在 Browse Samples 中选择、预览和导入一个或多个示例应用作为项目。其中每个示例都提供了 GitHub URL,我们还可以通过 GitHub 浏览源代码。通过 Browse Samples 查找和导入示例代码,请按如下步骤操作:依次选择 File > New > Import Sample:通过搜索框或滚动条浏览示例;当找到所需的示例时,突出显示该示例并查看预览:Tips:左列中突出显示了示例,右列中是该示例的预览如果要将其作为项目导入,请依次点击 Next 和 Finish:Browse Samples 提供了很多 Google 优质的示例项目,我们可以按需查找,导入后学习或者当作项目的基础版本。上图中我选择的 PictureInPicture 项目运行效果如下:6

2.1 重定向到路由地址

通过属性 redirect 指定重定向的路由地址:const router = new VueRouter({ routes: [ { path: '/a', redirect: '/b' } ]})示例:782代码解释:HTML 代码第 12-13 行,我们定义了两个跳转链接。HTML 代码第 15 行,我们使用 <router-view></router-view> 组件来渲染匹配组件。JS 代码第 5-7 行,我们定义了组件 Index。JS 代码第 9-11 行,我们定义了组件 Article。JS 代码第 13-17 行,我们定义了路由数组:根路由,地址为 ‘/’,重定向到路由地址 ‘/index’。首页路由,地址为 ‘/index’,匹配组件 Index。文章路由,地址为 ‘/article’,匹配组件 Article。JS 代码第 19-21 行,创建 router 实例,然后传 routes 配置。JS 代码第 25 行,通过 router 配置参数注入路由。

4.1 更新本地解释器路径

step1:打开项目, 访问解释器页面,Mac 下依次点击:主PyCharm -> Preference -> Project:项目名 -> Python Intepreter,Windows 和 Linux 下依次点击:File -> Settings -> Project:项目名 ->Python Intepreter。然后点击右上角的齿轮按钮:step2:在弹出列表中,单击"Show All…",会弹出“Project Interpreters" 对话框 。(选择 Add 要求你创建新的解释器)选择 Show All 会先查看有哪些存在的解释器,然后再决定是否创建新的。step3:可用的解释器出现在"Project Interpreters"对话框中,在对话框中选择期望的解释器。通过下面一排按钮为当前项目增删改解释器。红框中的按钮从上到下分别是:增加新的解释器;删除选中的解释器;编辑选中的解释器;与其他项目相关联的环境将不显示;选中解释器的现有路径将显示在解释器路径对话框中。点击上图按钮 4, 会显示下图:点击上图按钮 5, 会显示下图:

3.1 提交本地更改

主菜单 VCS -> View -> Tool Windows -> Commit,选择要提交的文件或者changelist, 填写提交信息,选择 commit 或者 Amend Commit通过工具栏上按钮,可以Rollback 代码,可以比较文件,也可以设置提交前与提交后的操作。有时候我们可能只想提交部分文件更改,比如在 test_rectangle.py, 增加了两个方法 test_width 与 test_height, 然后只提交 test_width。未选择的改变仍然在当前的Changelist 里。除此以外,也可以将一个文件更改放入不同的更改列表,以实现文件的部分提交。

3.1 临时节点和最小连接数策略实现负载均衡

首先我们需要在集群的每一个 Server 中都使用 Zookeeper 客户端 Curator 来连接 Zookeeper 服务端,当 Server 启动时,使用 Curator 连接 Zookeeper 服务端,并用自身的地址信息创建临时节点到 Zookeeper 服务端。我们还可以提供手动下线 Server 的方法,需要 Server 下线时可以手动调用删除节点的方法,需要 Server 上线时再次使用自身的地址信息来创建临时节点。除了维护 Server 的地址信息外,我们还需要维护请求的会话连接数,我们可以使用节点的 data 来保存请求会话的连接数。我们使用在 Zookeeper Curator 一节创建的 Spring Boot 测试项目来实现:/** * 最小连接数策略 Demo * Server 服务端注册地址 */@Componentpublic class MinimumConnectionsStrategyServer implements ApplicationRunner { @Autowired private CuratorService curatorService; // Curator 客户端 public CuratorFramework client; // 当前服务地址的临时节点 public static String SERVER_IP; // 当前服务地址临时节点的父节点,节点类型为持久节点 public static final String IMOOC_SERVER = "/imooc-server"; /** * 服务启动后自动执行 * * @param args args * @throws Exception Exception */ @Override public void run(ApplicationArguments args) throws Exception { // Curator 客户端开启会话 client = curatorService.getCuratorClient(); client.start(); // 注册地址信息到 Zookeeper registerAddressToZookeeper(); } /** * 注册地址信息到 Zookeeper * 服务启动时和服务手动上线时调用此方法 * * @throws Exception Exception */ public void registerAddressToZookeeper() throws Exception { // 判断父节点是否存在,不存在则创建持久节点 Stat stat = client.checkExists().forPath(IMOOC_SERVER); if (stat == null) { client.create().creatingParentsIfNeeded().forPath(IMOOC_SERVER); } // 获取本机地址 String address = InetAddress.getLocalHost().getHostAddress(); // 创建临时节点,节点路径为 /IMOOC_SERVER/address,节点 data 为 请求会话数,初始化时为 0. // /imooc-server/192.168.0.77 SERVER_IP = client.create() .withMode(CreateMode.EPHEMERAL) .forPath(IMOOC_SERVER + "/" + address, "0".getBytes()); } /** * 注销在 Zookeeper 上的注册的地址 * 服务手动下线时调用此方法 * * @throws Exception Exception */ public void deregistrationAddress() throws Exception { // 检查该节点是否存在 Stat stat = client.checkExists().forPath(SERVER_IP); // 存在则删除 if (stat != null) { client.delete().forPath(SERVER_IP); } }}在客户端的请求调用集群服务之前,先使用 Curator 获取 IMOOC_SERVER 下所有的临时节点,并寻找出 data 最小的临时节点,也就是最小连接数的服务。在客户端发送请求时,我们可以让当前 Server 的请求会话数加 1,并更新到临时节点的 data,完成请求时,我们可以让当前 Server 的请求会话数减 1,并更新到临时节点的 data 。/** * 最小连接数策略 Demo * Client 客户端发送请求 */@Componentpublic class MinimumConnectionsStrategyClient implements ApplicationRunner { @Autowired private CuratorService curatorService; // Curator 客户端 public CuratorFramework client; // 服务列表节点的 父节点 public static final String IMOOC_SERVER = "/imooc-server"; @Override public void run(ApplicationArguments args) throws Exception { // Curator 客户端开启会话 client = curatorService.getCuratorClient(); client.start(); } /** * 获取最小连接数的服务 * 发送请求前调用此方法,获取服务地址 * * @return String * @throws Exception Exception */ public String getTheMinimumNumberOfConnectionsService() throws Exception { // 获取所有子节点 List<String> list = client.getChildren().forPath(IMOOC_SERVER); // 新建 Map Map<String, Integer> map = new HashMap<>(); // 遍历服务列表,保存服务地址与请求会话数的映射关系 for (String s : list) { byte[] bytes = client.getData().forPath(IMOOC_SERVER + "/" + s); int i = Integer.parseInt(new String(bytes)); map.put(s, i); } // 寻找 map 中会话数最小的值 Optional<Map.Entry<String, Integer>> min = map.entrySet().stream().min(Map.Entry.comparingByValue()); // 不为空的话 if (min.isPresent()) { // 返回 服务地址 ip Map.Entry<String, Integer> entry = min.get(); return entry.getKey(); } else { // 没有则返回服务列表第一个服务地址 ip return list.get(0); } } /** * 增加该服务的请求会话数量 * 使用服务地址处理业务前调用此方法 * * @param ip 服务地址 * @throws Exception Exception */ public void increaseTheNumberOfRequestedSessions(String ip) throws Exception { byte[] bytes = client.getData().forPath(IMOOC_SERVER + "/" + ip); int i = Integer.parseInt(new String(bytes)); i++; client.setData().forPath(IMOOC_SERVER + "/" + ip, String.valueOf(i).getBytes()); } /** * 减少该服务的请求会话数量 * 请求结束时调用此方法减少会话数量 * * @param ip 服务地址 * @throws Exception Exception */ public void reduceTheNumberOfRequestedSessions(String ip) throws Exception { byte[] bytes = client.getData().forPath(IMOOC_SERVER + "/" + ip); int i = Integer.parseInt(new String(bytes)); i--; client.setData().forPath(IMOOC_SERVER + "/" + ip, String.valueOf(i).getBytes()); }}这样我们就使用 Zookeeper 的临时节点完成了一个简单的最小连接数策略的负载均衡。

4. 共享本地历史

本地历史记录不支持共享访问,它存储在本地,仅供个人使用。但是,我们还是可以创建一个 Patch 文件,该文件包含相对于特定修订版的更改,这样就可以与他人共享这些更改。本地历史记录对话框中选择修订版,然后右键上下文菜单选择 Create Patch 或者点击工具栏上对应按钮。.Patch 修补程序是用于共享更改,无需将它们签入 VCS 存储库, 然后通过其它方式,比如电子邮件发送给其它人实现共享,在实际工作并不是经常用,有兴趣的话请看相关文档。

2.2 Map 的属性和方法

Map 提供的属性和方法从增、删、改、查几个方面入手,主要有以下 5 种:方法名描述set接收键值对,向 Map 实例中添加元素get传入指定的 key 获取 Map 实例上的值delete传入指定的 key 删除 Map 实例中对应的值clear清空 Map 实例has传入指定的 key 查找在 Map 实例中是否存在size属性,返回 Map 实例的长度Map 提供 size 属性可以获取 Map 实例上的长度var map = new Map([["x", 1], ["y", 2], ["z", 3]]);console.log(map.size) // 3set() 方法为 Map 实例添加或更新一个指定了键(key)和值(value)的键值对。myMap.set(key, value);通常情况下不会一开始就初始化值,而是动态地添加,或更新 Map 时需要用到 set 方法,可以新增和修改 Map 实例的值。而且 key 值可以是任意类型的,查看如下示例:var map = new Map();var str = 'string';var obj = {};var arr = [];var fun = function() {};map.set(str, '键的类型字符串');map.set(obj, '键的类型对象');map.set(arr, '键的类型数组');map.set(fun, '键的类型函数');上面的代码中,我们定义了不同类型的变量,使用这些变量为 map 添加数据。相比 Object 对象,扩展性更强了。另外还可以链式添加键值对:var map = new Map();map.set('a', 1).set('b', 2).set('c', 3);console.log(map); // Map(3) {"a" => 1, "b" => 2, "c" => 3}使用链式添加键值对的方式比较简洁,如果需要添加多个值,建议使用这样的方式去添加。get() 方法是接收一个指定的键(key)返回一个 Map 对象中与这个指定键相关联的值,如果找不到这个键则返回 undefined。myMap.get(key);使用上面的示例,可以通过 get 方法获取对应的值:console.log(map.get('string')); // "键的类型字符串"console.log(map.get(str)); // "键的类型字符串"console.log(map.get(obj)); // "键的类型对象"console.log(map.get(arr)); // "键的类型数组"console.log(map.get(fun)); // "键的类型数组"上面的代码可以看出,我们可以直接使用键的值去获取 Map 实例上对应的值,也可以通过定义变量的方式去获取。has() 方法是用于判断指定的键是否存在,并返回一个 bool 值,如果指定元素存在于 Map 中,则返回 true,否则返回 false。myMap.has(key);实例:var map = new Map();map.set("a", 11);map.has("a"); // truemap.has("b"); // falsedelete() 方法用于移除 Map 实例上的指定元素,如果 Map 对象中存在该元素,则移除它并返回 true;否则如果该元素不存在则返回 false。myMap.delete(key);实例:var map = new Map();map.set("a", 11);map.delete("a"); // truemap.has("a"); // falseclear() 方法会移除 Map 对象中的所有元素,返回 undefined。myMap.clear(key);实例:var map = new Map();map.set("a", 11);map.clear(); // 返回 undefined这里需要注意的是 clear() 返回的值是 undefined 而不是 true 所以如果在判断结果的时候需要注意这一点。

2. 回调地狱

我们都知道 JavaScript 异步使用的是回调函数,下面我们来看一个 ajax 请求的实例,下面的 ajax 方法是一个伪代码,可以看作是请求接口的方法,接口请求的库可以参考 jQuery 的 $.ajax 和 axios。// ajax请求的伪代码function ajax(url, sucessCallback, failCallback) { // url:请求的url // sucessCallback:成功的回调函数 // failCallback:失败的回调函数}ajax(url1, (res1) => { ajax(url2, (res2) => { ajax(url3, (res3) => { doSomething(res1, res2, res3) }) })})上面的 ajax 请求我们可以理解为,在调用 doSomething 方法时需要前面三个请求的结果作为参数,所以只有前一个 ajax 请求得到结果后才能发起第二个请求。这样前后有依赖的嵌套被称为回调地狱。对于比较复杂逻辑的情况来说,回调地狱会使程序出问题的概率大大增加。另外,这样做有个很严重的问题,就是接口请求的时间是三个请求的和,不能进行并发操作,当然我们也可以做一些优化操作,如下:let out = after(3, function (data){ doSomething(...data)})ajax(url1, (res1) => { out(res1)})ajax(url2, (res2) => { out(res2)})ajax(url3, (res3) => { out(res3)})function after(times, callback) { const arr = []; return function (value){ arr.push(value); if (--times==0) { callback(arr); } }}上面的代码很优雅地解决了回调嵌套的问题,但同时我们需要手动维护一个计数器来控制最后的回调。这无疑增加了程序的复杂度,我们更希望的是关注我的业务,而不是写更多的逻辑来优化。针对这种情况,社区提供了很多这类优化的库,而 Promise 则是其中最亮眼的。对上面的情况,Promise 怎么解决的呢?看如下的实现方式:function request(url) { return new Promise((resolve, reject) => { ajax(url, (res) => { resolve(res) }) })}Promise.all([request(url1), request(url1), request(url1)]).then((result) => { doSomething(...result)}).catch((error) => { console.log(error)})上面的代码中我们封装了一个 request 请求的方法,通过 Promise.all() 来并发请求这些接口,当接口都正确返回才会执行 then 方法中的回调,有一个错误都会抛出异常。这种方式比较好的是,我们对请求进行了封装,不要再关注每一步请求是否完成做对应的逻辑处理,让我们在开发过程中更加关注业务逻辑,使开发效率更快。

6. 更轻松地迁移

由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,其运行结果是一致的。用户可以很轻易地将应用迁移到另一个平台上,不用担心运行环境的变化。

2.3 本地仓库

本地仓库可以简单理解成一个目录,这个目录里面的所有文件都被 Git 管理,Git 记录了每个文件的修改、删除,因此我们可以对历史版本进行查看或者还原。那么,如何创建一个版本库呢?(说明:以下内容作为 “本地仓库” 概念的辅助理解,具体命令操作后续会更多接触,先不用纠结)  a. 选择一个合适的地方,创建一个空目录。  b. 在目录下执行:git init 命令即可初始化一个本地仓库。  c. 之后当前目录会出现一个隐藏的.git 的目录,这个目录是 Git 来跟踪管理版本库的,不要手动修改这个目录里面的文件,否则会把 Git 仓库给破坏了。  d. 本地仓库初始化完成后,我们就可以在本地仓库进行文件的管理。

2. 给特定状态本地历史记录加标签

本地历史记录修订通常标有时间戳,不容易导航。可以添加新标签来标记本地历史记录的当前状态,例如,在开始大规模重构之前。主菜单 VCS -> Local History -> Put Label 或者在编辑器内右键菜单 Local History -> Put Label, 在打开对话框内输入一个意义的名字标记当前代码状点,然后点击 OK 。再次查看该文件历史,创建标签是被显示在当前状态行上。

1. 查看本地关联的远程仓库

还记得上节课讲如何初始化一个本地 git 仓库的时候,我们用到了从远程仓库拉取到本地的那种方式吗?忘记了的可以回去翻看下上一节内容,就是这个命令,还记得吗?$ git clone 远程仓库URL当我们从远程仓库与本地同步后,那么本地即与远程仓库进行了关联操作。我们就可以通过如下命令查看关联的远程仓库:$ git remote或者是查看更详细的信息:$ git remote -v具体操作步骤如下:

2. 利用 arcTo 方法绘制弧线

arcTo() 是利用两条相交切线来确定圆弧的位置,开始前我们先要搞懂切线的几个知识点。如何确定切线?我们都知道两点确定一条直线,这里两条直线相交处有一个交点,交点是两条线共用的一个点,所以我们只需要三个点就能确定两条切线。根据切线如何确定圆心?切线的性质有:(1)切线和圆只有一个公共点。(2)切线和圆心的距离等于圆的半径。(3)切线垂直于经过切点的半径。(4)经过圆心垂直于切线的直线必过切点。(5)经过切点垂直于切线的直线必过圆心。我们根据切线的垂直线必过圆心,即可确定圆心。我们来看一张图片:上图中,只要我们确定了 PA、PB 这两条切线和圆的半径 OA,即可确定 AB 这条弧线。上图中,我们沿着 OP 延长线移动 O 点的位置,即可得到半径不同的圆,也就得到了不同的 AB 弧线。到这里我们明白了:有三个点就可以确定两条切线。有圆的半径就可以确定切线间的一条弧线。arcTo 就是利用上面的原理来绘制弧线的。arcTo 方法有5个参数,前两个参数表示的是上图中 P 点的坐标,也就是切线的交点,第3个和第4个参数表示 PB 切线上的任意一个坐标点,第5个参数表示的是上图中 OA 的长度,也就是绘制圆的半径。特别注意:第3、4个参数表示的点不是切点!第3、4个参数表示的点不是切点!第3、4个参数表示的点不是切点!arcTo 方法的参数中只有两个点和一个半径,我们前面讲到要绘制弧线,必须是三个点,那第一个点哪儿去了呢?其实第一个点就是当前画布中笔触所在的位置,也就是当前画布中已经绘制的路径的终点。先看整体案例:1433运行结果:我们对上面的绘制弧线代码做拆分讲解:开始一个新路径。ctx.beginPath();确定第一个坐标点 A 点,A 点是当前已有路径的终点。ctx.moveTo(40,40);我换一个写法:ctx.moveTo(40,0);ctx.lineTo(80,40);这时候 A 点的位置就变成了 (80, 40)。 根据切线交点、第二条切线上的某个点和半径开始绘制弧线。ctx.arcTo(260,40, 260,200, 60); //调用了绘制圆的函数这里需要注意三点:(1) A 点和 PA 切线的切点会被自动连接起来,但是 PB 切线上的切点和 B点不会自动连接起来。 (2) A 点肯定在路径上,B 点不一定在路径上。(3) 切点由 canvas 自动计算。设置绘制样式以及开始描边。ctx.strokeStyle = "#456795";ctx.lineWidth = 4;ctx.stroke();我们从案例中可以看到,绘制一个圆形路径只需要调用一个函数即可,arc 方法和我们之前学过的 rect 绘制矩形的方法类似,也是绘制了一个路径,我们后续对路径的描边或者填充依然是需要调用 stroke 或者 fill 方法的。

5. 更新本地历史记录的保留期

默认情况下,本地历史记录配置为存储过去 5 个工作日, 这个值可以被更新。主菜单 Help -> Find -> Action, 查找并打开 Registry, 修改localHistory.daysToKeep参数的值。单击关闭并重新启动 PyCharm 以使更改生效。

4.2 上线推送

private void login(LoginReqBean bean, Channel channel){ Channel c=map.get(bean.getUserid()); LoginResBean res=new LoginResBean(); if(c==null){ //1.添加到map map.put(bean.getUserid(),channel); //2.给通道赋值 channel.attr(AttributeKey.valueOf("userid")).set(bean.getUserid()); //3.登录响应 res.setStatus(0); res.setMsg("登录成功"); res.setUserid(bean.getUserid()); channel.writeAndFlush(res); //4.根据user查找是否有尚未推送消息 //思路:根据userid去lists查找....... }else{ res.setStatus(1); res.setMsg("该账户目前在线"); channel.writeAndFlush(res); }}

5. Spring Boot 的江湖地位

由于 Spring Boot 设计优雅,实现简单,可以节省不少开发时间。从此,程序员们有了更多时间去陪妹子逛街买裙子。没有女朋友的小伙伴们,也有了更多时间思考追女孩的方案(一定要勇敢地行动呀)。从一定程度上讲,Spring Boot 降低了程序员群体的单身比例。所以 Spring Boot 的火爆是必然的,据了解,Spring Boot 框架已经是 Java 企业级应用开发的主流框架了。另外由于微服务的火爆,作为 Spring Cloud 实现基础的 Spring Boot ,更是春风得意,风头一时无两。从 Spring Boot 在 Spring 官网的菜单位置,可以一瞥 Spring Boot 的地位所以不管出于哪种目的,为跳槽、为加薪、为方便、为省心、为学习、为进步、为爱情、为家庭,Spring Boot 都是 Java 开发旅途的重要风景。而我,本系列文章的作者,愿陪你看万山红遍、层林尽染,用尽量轻松的语言,讲一些编程的故事和经验,陪你度过一段愉快的 Spring Boot 学习时光。

2.3 多个 K 线图

由于 k 线图的数据项只能通过这种 4 位数组的格式定义,这会导致 k 线图与折线图、柱状图、散点图等其他直角坐标图表有些许不同:x、y 轴中必须有一条是类目轴,根据用户习惯,通常会选择 x 轴做类目轴;k 线图无法通过series.data 推断类目属性,所以类目轴必须通过 axis.data 项显式声明类目数据;k 线图的 series.data 与类目轴的 axis.data 根据数据出现的位置关联。当序列上只有一个 k 线图时,问题不大,但若要在同一坐标系上渲染多个 k 线图时,则需要对数据做一些额外的处理。比如,假设要展示下述四种蔬果的价格变化:[ { sku: '小台农芒果', data: [ ['2020-3-4', 9, 7, 14, 1], ['2020-3-6', 7, 3, 12, 1], ['2020-3-9', 3, 2, 8, 1], ['2020-3-12', 2, 1, 5, 1], ['2020-3-14', 1, 4, 6, 1], ['2020-3-16', 4, 7, 3, 1], ['2020-3-19', 7, 10, 3, 1], ['2020-3-21', 10, 12, 6, 1], ['2020-3-23', 12, 15, 5, 1], ['2020-3-25', 15, 13, 8, 1], ], }, { sku: '阿克苏苹果', data: [ ['2020-3-3', 6, 7, 13, 4], ['2020-3-6', 7, 5, 8, 3], ['2020-3-8', 5, 8, 11, 3], ['2020-3-9', 8, 11, 15, 2], ['2020-3-10', 11, 9, 13, 5], ['2020-3-11', 9, 12, 20, 2], ['2020-3-12', 12, 9, 16, 6], ['2020-3-15', 9, 11, 13, 6], ['2020-3-17', 11, 14, 19, 8], ['2020-3-19', 14, 17, 21, 11], ], }, { sku: '海南西州蜜瓜', data: [ ['2020-3-1', 16, 17, 23, 11], ['2020-3-2', 17, 15, 24, 10], ['2020-3-4', 15, 12, 20, 6], ['2020-3-7', 12, 9, 16, 3], ['2020-3-9', 9, 6, 12, 1], ['2020-3-12', 6, 3, 8, 1], ['2020-3-14', 3, 0, 5, 1], ['2020-3-17', 0, 2, 6, 1], ['2020-3-19', 2, 5, 8, 1], ['2020-3-21', 5, 8, 11, 1], ], }, { sku: '泰国椰青', data: [ ['2020-3-2', 18, 21, 22, 14], ['2020-3-3', 21, 19, 28, 13], ['2020-3-4', 19, 22, 27, 17], ['2020-3-6', 22, 21, 27, 17], ['2020-3-7', 21, 22, 24, 13], ['2020-3-9', 22, 21, 26, 16], ['2020-3-11', 21, 19, 23, 12], ['2020-3-13', 19, 21, 25, 15], ['2020-3-16', 21, 22, 23, 15], ['2020-3-18', 22, 20, 29, 19], ], },];注意,四个系列的统计时间不同,由于 k 线图无法自动推算类目轴的类别数据,所以第一步需要收集所有类目值:function retriveDates(series) { const categories = []; const len = series.length; for (let i = 0; i < len; i++) { // 找出尚未收集的时间值 const dates = series[i].data .map(([date]) => date) .filter((date) => categories.findIndex((cat) => cat === date) < 0); // 批量插入 categories.splice(categories.length, 0, ...dates); } return categories;}第二步,需要根据应用场景对收集到的类目值进行排序,本例中为简便起见,将借助 moment 库进行时间排序:function sort(categories) { const format = 'YYYY-MM-DD'; return categories.sort((d1, d2) => moment(d1, format) - moment(d2, format));}第三步,有了类目数据之后,还需要整理系列数据的顺序,使得数据与其对应的类目能够一一对应:function reschedule(series, categories) { return series.map(({ sku, data }) => { return { name: sku, data: categories.map((cat) => { const index = data.findIndex((c) => c === cat); return index >= 0 ? data[index].slice(1) : null; }), }; });}经过上述步骤就可以得到所有类目值及调整后的系列数据,完整代码:1375示例效果:

查找文件和目录

实际工作中文件多了,可能就会忘掉它的位置,这个时候就可以使用 find 命令快速查找出文件所在目录的地址,提升了文件查找的效率。

3. Map 和 Object

Map 和 Object 有非常多的相似的地方,Map 的出现也是为了弥补 Object 的不足。 Object 的键只能是字符串,Map 的键可以是任意类型的值(包括对象),所以 Map 是一种更完善的 Hash 结构实现。

首页上一页1234567下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号