Commit e82e89e8 authored by wangxuxiao's avatar wangxuxiao
parents b06306b7 9ec353cc
This diff is collapsed.
This diff is collapsed.
---
title: Docker 基础使用介绍
date: 2022/05/30 9:25:23
updated: 2022/05/30 9:25:23
tags:
- docker
- 容器
- 虚拟化
author: 蔡海飞
---
> Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。我们可以通过将开发代码打包到docker 镜像中,上传到docker hub中,待发布时通过拉取docker hub镜像启动docker 容器,实现代码运行环境的高度一致,并提高部署效率。
![docker运行系统图](/yifu-study-front-share/images/docker-system.png)
本篇文章就我们较为常用的docker 命令使用通过场景使用的不同来简单介绍。
<!-- more -->
### Docker 安装与镜像加速
#### Docker安装
docker 提供了各种不同系统的安装方式,因为我们常用的正式部署环境使用centos的缘故,我这里只介绍centos里如何安装docker以及如何配置docker国内镜像加速。
1. 使用官方提供的脚本自动安装
```
$ curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
```
2. 手动命令行安装
```
# 先卸载旧版本的docker安装包,后安装新版
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
```
#### 镜像加速
1. 阿里云
```
$ sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
```
2. 清华大学源
```
$ sudo yum-config-manager \
--add-repo \
https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
```
3. 腾讯源
```
$ sudo yum-config-manager \
--add-repo \
https://mirror.ccs.tencentyun.com/docker-ce/linux/centos/docker-ce.repo
```
#### 启动docker 服务
```
$ sudo systemctl restart docker
```
### Docker 核心概念
![docker-system.jpeg](/yifu-study-front-share/images/docker-system.jpeg)
#### 镜像
Docker镜像是由文件系统叠加而成。一个镜像可以多个中间层组成,多个镜像可以共享同一中间层,我们也可以通过在镜像添加多一层来生成一个新的镜像。镜像在构建完成之后,便不可以再修改,而上面我们所说的添加一层构建新的镜像,这中间实际是通过创建一个临时的容器,在容器上增加或删除文件,从而形成新的镜像,因为容器是可以动态改变的。整理可以得出镜像的两个特点:
- 镜像是分层的
- 镜像是只读的
![docker-image.png](/yifu-study-front-share/images/docker-image.png)
1. 常用命令
```shell
$ docker image ls # 枚举本地主机中的docker镜像
$ docker image inspect nginx:latest # 获取nginx:latest镜像的层数据和元数据
$ docker rmi nginx:latest # 删除本地的nginx:latest,需要先删除应用该镜像的容器
$ docker tag nginx:latest nginx:test # 给本地nginx:latest镜像添加标签nginx:test
$ docker commit -a a404c6c174a2 mymysql:v1 # 基于当前容器a404c6c174a2创建新的镜像mymysql:v1
$ docker build -f Dockerfile -t myimage:0.0.1 . # 基于Dockerfile文件制作镜像myimage:0.0.1
```
#### 容器
容器是镜像的运行时实例。正如从虚拟机模板上启动 VM 一样,用户也同样可以从单个镜像上启动一个或多个容器。虚拟机和容器最大的区别是容器更快并且更轻量级——与虚拟机运行在完整的操作系统之上相比,容器会共享其所在主机的操作系统/内核。
Docker 容器是一个开源的应用容器引擎,让开发者可以以统一的方式打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何安装了docker引擎的服务器上(包括流行的Linux机器、windows机器),也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app)。几乎没有性能开销,可以很容易地在机器和数据中心中运行。最重要的是,他们不依赖于任何语言、框架包括系统。
1. 常用命令
```shell
$ docker ps -a # 列出当前主机中所有的docker容器
$ docker run -it nginx /bin/bash # 基于nginx镜像启动一个docker容器
$ docker pause containername # 暂停docker 容器
$ docker start containername # 启动docker容器
$ docker stop containername # 停止docker容器
$ docker restart containername # 重启docker容器
$ docker attach -it containername /bin/bash # 进入docker 容器,此种方式进入退出后会使得docker容器停止
$ docker exec -it containername /bin/bash # 进入docker 容器,此种方式进入退出后不会使得docker容器停止
$ docker export containername > containername.tar # 导出docker容器快照
$ docker rm containername # 删除docker 容器
$ docker logs -f containername # 持续输出docker容器的日志信息
$ docker cp containerID:container_path host_path # 复制主机文件到对应docker容器的地址
```
#### 仓库
Docker 仓库是用来包含镜像的位置。Docker提供一个注册服务器(Register)来保存多个仓库,每个仓库又可以包含多个具备不同tag的镜像。Docker运行中使用的默认仓库是 Docker Hub 公共仓库。
![docker-hub.png](/yifu-study-front-share/images/docker-hub.png)
1. 常用命令
```shell
$ docker pull nginx:latest # 从镜像仓库拉取nginx:latest镜像
$ docker search nginx # 搜索镜像库的nginx相关镜像
$ docker push nginx:0.0.1 # 提交本地镜像nginx:0.0.1到当前登录的镜像仓库
```
### 一个简单的docker 使用示例
1. 制作Dockerfile文件
```shell
# Dockerfile 文件
FROM nginx:alpine
ADD deploy/qas/default.conf /etc/nginx/conf.d
ADD dist /home/html/app/
# deploy/qas/default.conf
server{
listen 8080;
location ^~ /proxy-path/ {
#自定义头信息传递
proxy_pass http://****/;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
}
location / {
#配置代理参数
proxy_redirect off;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host:$server_port;#这里是重点,这样配置才不会丢失端口
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
root /home/html/app/;
index index.html;
try_files $uri /index.html;
}
}
# dist为打包文件
```
2. 制作Docker镜像
```shell
$ docker build -f ./deploy/qas/Dockerfile -t website:0.0.1 .
```
3. 上传Docker镜像
```shell
$ docker tag website:0.0.1 website/test
$ docker images
$ docker push website/test
```
4. 启动docker 容器
```shell
$ docker pull website/test
$ docker run -it --name website-test -p 80:80 -d website/tes
```
5. 查看docker 容器运行状态
```shell
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
90cdb9ad1ae1 website/tes "nginx -g 'daemon of…" a minute ago Up a minute 0.0.0.0:80->80/tcp website-test
```
\ No newline at end of file
---
title: 性能优化---Preload&Prefetch
date: 2022/5/7 14:06:20
tags:
- 前端
- 盒子模型
- CSS
author: 刘磊
---
# 性能优化---Preload&Prefetch
在preload和prefetch之前,我们一般根据编码需求通过link或者script标签引入页面渲染和交互所依赖的js和css等;然后这些资源由浏览器决定优先级进行加载、解析、渲染等。
然而,有些情况我们需要某些依赖在浏览器进入渲染的主进程之前就希望被加载,但是实际资源加载的状况并不受我们控制,而是根据浏览器内部决定资源的优先级等状况进行加载的。即使我们将需要的资源按照希望的那样放在期望的位置,但是由于资源的加载和解析,尤其是js的加载、解析和编译是阻塞式的,因此往往还是达不到预期。或者,有些资源是我们后边需要的,我们希望在需要它的时候在进行解析和执行,并不想让它的加载影响其他资源的加载及首屏渲染时间。
preload和prefetch的出现为我们提供了可以更加细粒度地控制浏览器加载资源的方法。
```
<link ref='preload'>
<link ref='prefetch'>
```
<!-- more -->
#### preload特点
- preload加载的资源是在浏览器渲染机制之前进行处理的,并且不会阻塞onload事件;
- preload可以支持加载多种类型的资源,并且可以加载跨域资源;
- preload加载的js脚本其加载和执行的过程是分离的。即preload会预加载相应的脚本代码,待到需要时自行调用;
#### prefetch特点
- prefetch加载的资源可以获取非当前页面所需要的资源,并且将其放入缓存至少5分钟(无论资源是否可以缓存);并且,当页面跳转时,未完成的prefetch请求不会被中断;
#### preload和prefetch对比
- preload主要用于预加载当前页面需要的资源;而prefetch主要用于加载将来页面可能需要的资源;
- 不论资源是否可以缓存,prefecth会存储在net-stack cache中至少5分钟;
- preload需要使用as属性指定特定的资源类型以便浏览器为其分配一定的优先级,并能够正确加载资源;
## webpack中的perload和perfetch
问题:异步加载模块是Webpack官方所希望开发者实现的,而且异步加载也能提升首页加载速度,但是又会导致异步加载的那部分代码逻辑迟迟不能执行,可能导致用户的交互长时间没有响应。
所谓预取,就是提前获取将来可能会用到的资源。prefetch chunk会在父chunk加载完成之后进行加载。
那么该怎么做呢?我们要通过一种称作Magic Comment(魔法注释)的方式,让Webpack输出"resource hint(资源提示)",来告知浏览器。
```
document.getElementById('btn').onclick = function () {
import( /* webpackChunkName: 'base',webpackPrefetch:true*/ './base').then(({
mul
}) => {
console.log(mul(40, 3));
}).catch((err) => {
console.log(`base.js加载失败:${err}`);
});
}
```
---
title: TypeScript泛型
date: 2022/5/10 16:00:00
tags:
- 前端
- typescript
author: 杨靖
---
## 泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
我们可以用一个函数createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值:
```typescript
function createArray(length: number, value: any): Array<any> {
let result = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
```
上例中,我们使用了之前提到过的数组泛型来定义返回值的类型。
这段代码编译不会报错,但是一个显而易见的缺陷是,它并没有准确的定义返回值的类型:
Array<any> 允许数组的每一项都为任意类型。但是我们预期的是,数组中每一项都应该是输入的 value 的类型。
这时候,泛型就派上用场了:
<!-- more -->
```typescript
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray<string>(3, 'x'); // ['x', 'x', 'x']
```
上例中,我们在函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array<T> 中即可使用了。
接着在调用的时候,可以指定它具体的类型为 string。当然,也可以不手动指定,而让类型推论自动推算出来:
```typescript
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
```
*定义泛型的时候,可以一次定义多个类型参数:*
```typescript
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
swap([7, 'seven']); // ['seven', 7]
```
上例中,我们定义了一个 swap 函数,用来交换输入的元组。
**泛型约束**
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:
```typescript
function loggingIdentity<T>(arg: T): T {
console.log(arg.length);
return arg;
}
// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.
```
上例中,因为泛型 T 不一定包含属性 length,所以编译的时候报错了,是一个错误的例子。
这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束:
```typescript
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
```
上例中,我们使用了 extends 约束了泛型 T 必须符合接口 Lengthwise 的形状,也就是必须包含 length 属性。
此时如果调用 loggingIdentity 的时候,传入的 arg 不包含 length,那么在编译阶段就会报错了:
```typescript
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity(7);
// index.ts(10,17): error TS2345: Argument of type '7' is not assignable to parameter of type 'Lengthwise'.
```
多个类型参数之间也可以互相约束:
```typescript
function copyFields<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = (<T>source)[id];
}
return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 };
copyFields(x, { b: 10, d: 20 });
```
上例中,我们使用了两个类型参数,其中要求 T 继承 U,这样就保证了 U 上不会出现 T 中不存在的字段。
**泛型接口**
使用接口的方式来定义一个函数需要符合的形状:
```typescript
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
```
当然也可以使用含有泛型的接口来定义函数的形状:
```typescript
interface CreateArrayFunc {
<T>(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc;
createArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
```
```typescript
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc<any>;
createArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
```
*使用泛型接口的时候,需要定义泛型的类型。*
**泛型类**
与泛型接口类似,泛型也可以用于类的类型定义中:
```typescript
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
```
**泛型参数的默认类型**
在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。
```typescript
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
```
......@@ -4,7 +4,7 @@ date: 2022/4/22 17:30:00
tags:
- 前端
- typescript
author: 杨靖
author: 杨靖
---
## typescript的高级类型详解
......
---
title: 性能优化--通过优化首屏加载速度实现
date: 2022/5/24 14:30
tags:
- 前端
- 路由懒加载
- 性能优化
author: 刘磊
---
#### 什么是路由懒加载
路由懒加载也叫延迟加载,即在需要的时候进行加载,随用随载。在单页面应用中浏览器默认会将所有的资源全部下载下来,这可能会导致首屏加载的时间过长。路由懒加载可以做到点击对应的路由再加载对应的文件资源
#### 路由懒加载的三种写法 (推荐用法:es6的import)
1. component: resolve => require(['../pages/home], resolve)
1. component: import(/* webpackChunkName: 'ImportFuncDemo' */ '../pages/home')
1. component: resolve=>{require.ensure(,()=>{resolve(require('../pages/home'))})}
#### 路由懒加载使用中的疑惑
项目中已经使用了路由懒加载为什么首屏渲染仍然请求了所有路由的chunk;
解答:vue-cli webpack中默认配置了prefetch这个功能可以在浏览器闲置时加载网站未来可能会用到的资源;但
经过验证这个prefetch预请求阻塞了首屏的加载
#### 解决prefetch影响首页加载问题
- 在webpack配置中删除prefetch插件
```
configplugins.delete(prefetch)
```
<!-- more -->
- 在引用时配置
```
import(<!--webpackChunkName:'[...]',webpackPrefetch:false-->)
```
#### 思考:既然可以通过import异步加载路由组件,非路由组件是否可以通过异步加载的方式,从而优化首屏的加载速度?很多情况中复杂的弹窗等组件比页面组件的资源更大。
- 经过查阅文档发现VUE官方也提到了异步组件,并有相关的用法
- 通过异步引入的弹窗组件从主包分离出来,但是仍然在首页加载是就将弹窗组件加载出来。并未实现点击组件时
再去加载文件:
```
const wechatEnter = () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import(
/*webpackChunkName:'wechatEnter',webpackPrefetch:true */ '@/views/index/components/wechatEnter.vue'
),
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000,
})
```
#### 利用webpack——SplitChunks优化
SplitChunks 插件来控制 Webpack 打包生成的 js 文件的内容的精髓在于:防止模块被重复打包,拆分过大的js
文件,合并零散的js文件;
##### 每个浏览器并发请求数量不同,分包需要考虑并发
由于并发数量的限制,对于splitchunks的分包并不是越多越好。需要具体情况具体分析,比如并发请求数量设置为4,目前有三个包一个包体积较大,那么这时候对大包拆成两个包加载速度肯定会有提升;如果本来有4个包,并发数量也是4,这时候拆个包出来如果包的体积也不大,第5个包请求的时间加上队列之间多出来的时间,综合下来谁快谁慢还不好说;最好的办法还是对静态资源做多域名请求;
#### 通过CDN引入第三方库,但是这个有风险,就是第三方库挂掉或者什么的,可以选择付费的cdn加速。或者下载到本地上传到自己的服务器,总共三套方案,可以同时使用,保证安全性。
#### 静态资源压缩,代码压缩,图片压缩;gzip压缩一定要开,并且服务端配合开一下,真的很重要。开启gzip后你会发现加载速度有质的提升,尤其是你的vendor.js和app.js体积过大的时候。
#### 代码层面的优化
This diff is collapsed.
......@@ -202,7 +202,7 @@ XLSX.utils.decode_range("B1:C9"); //{s:{c: 1, r: 0},e: {c: 2, r: 8}}
- readingOrder:文字方向,值为数字0(根据内容决定)、1(从左到有) 或 2(从右到左)
- textRotation:文本旋转角度,值为数字,0至180或 255(垂直排列) ,默认为0
`alignment`: 对其属性,其子属下如下:
`border`: 边框属性,其子属下如下:
- top:上边框样式,值为对象,如:{style: 'thin', color:{rgb: "FFFFAA00"}},其中,style的值集包括:thin、medium、thick、dotted、hair、dashed、mediumDashed、dashDot、mediumDashDot、dashDotDot、mediumDashDotDot、slantDashDot、double
- bottom: 下边框样式,值同top
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment