前端搞搞基建(三)

前端大基建

“基建”,就是研发团队的技术基础设施建设,是一个团队通用技术能力的沉淀,是一个团队未来的保证。网上看到的一句话,说的很好,“业务支撑是活在当下,技术基建是活好未来”。

源码和更多案例放在github上面,欢迎star


前端基建链路层

基建的内容和业务阶段团队既有建设的沉淀是分不开的,所以基建就是从最基础的部分开始搞,怎么样能规范流程,方便开发,方便维护,怎样 能更加优雅的扩展业务,就怎么去搞基建。

接下来我们以“基建链路层”来搭建基建系统,下面是我所整理的基建链路层:

在这里插入图片描述

性能、错误监控方案

性能监控

前端性能监控指标

  • 白屏时间:用户从打开页面开始到页面开始有东西呈现为止;

  • 首屏时间:用户浏览器首屏内所有内容都呈现出来所花费的时间;

  • 用户可交互时间:用户可以进行正常的点击、输入等操作,默认可以统计domready时间,因为通常会在这时候绑定事件操作;

  • 总下载时间:页面所有资源都加载完成并呈现出来所花的时间,即页面 onload 的时间。

性能监控工具

1.非侵入式(通过运行外部插件监控项目的形式)

  • pagespeed(谷歌开发的分析优化网页工具)
  • Yslow (是Yahoo发布的一款基于FireFox的插件)
  • WebPagetest(网上开源项目)

2.侵入式

  • Performance (是前端性能监控的API。它可以检测页面中的性能,W3C性能小组引入进来的一个新的API,它可以检测到白屏时间、首屏时间、用户可操作的时间节点,页面总下载的时间、DNS查询的时间、TCP链接的时间等)

错误监控

Sentry 简介

Sentry 是一个开源的实时错误报告工具,支持 web 前后端、移动应用以及游戏,支持 Python、OC、Java、Go、Node、Django、RoR 等主流编程语言和框架 ,还提供了 GitHub、Slack、Trello 等常见开发工具的集成。

Sentry有网上的收费版本,如果不想购买,可以在自己服务器上搭建一个,sentry是开源代码。

Sentry 安装

sentry的话建议用docker安装,方便快捷,开源代码现在也是主推docker安装

github:https://github.com/getsentry/sentry

1.安装docker

sudo yum -y install docker-io

2.启动docker

service docker start

3.安装Docker-compose:

curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

4.克隆 git clone https://github.com/getsentry/onpremise.git 按照remind.md 一步步操作

如果执行过程中一切正常的话,在浏览器中输入http://ip:9000 就进入 Sentry 的登录页面了,使用上面创建的管理员用户名和密码登录系统。

在这里插入图片描述


Web缓存架构

web开发,怎么都离不开缓存的问题。

举个例子:一般玩的单机游戏,往往都容量都非常大(几十G,乃至上百G),轻轻松松都超过了电脑内存(8G,16G),所以很明显的,在游戏的运行过程中,不可能整个游戏都放入内存中。如果都放在硬盘,或者移动硬盘里面,每次都要去读取,读取速度慢怎么办呢。该怎么解决问题?

这里就要说一下缓存局部原理了,可以分为时间和空间两个维度。

  • 时间维度:曾经或者现在使用的数据,往往在之后会再次被使用
  • 空间维度:被使用数据的关联数据,往往会被使用

局部性原理是在内存,高速缓存部分,提出来用于解决问题的

缓存是一个到处都存在的用空间换时间的例子。通过使用多余的空间,我们能够获取更快的速度。

分类

  • 1.浏览器缓存

    • Cookie
    • LocalStorage
    • SessionStorage
    • 基于浏览器的强缓存和缓存协商(last-modified,expries,cache-control,Etag)
  • 2.CDN缓存

    • CDN边缘节点缓存
  • 3.代理服务器缓存

    • Nginx缓存模块
  • 4.数据库缓存

    • Mysql
  • 5.外部缓存

    • Redis

浏览器缓存。

一.cookie

由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的。Cookie诞生的最初目的是为了存储web中的状态信息,以方便服务器端使用。比如判断用户是否是第一次访问网站。目前最新的规范是RFC 6265,它是一个由浏览器服务器共同协作实现的规范。

特点:

1.域的限制

2.时间限制

3.空间限制,cookie只能存储4kb

4.数量限制,每个域下最多不能超过50个cookie

5.存储数据类型限制,cookie只能存储字符串

注意:cookie是不安全的,不能存一些私密数据。另外cookie是可以通过http请求的方式在http请求头被带到后端服务器的。

二.LocalStorage && SessionStorage

特性LocalStorageSessionStorage
生命周期除非被主动清楚,不然会一直存在浏览器窗口会话期间
存放数据大小5M 或者更大(不同浏览器可能不同5M 或者更大(不同浏览器可能不同)

不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标 签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。

三.基于浏览器的缓存协商(last-modified,expries,cache-control,Etag)

这个在我一篇文章有详细的描述

CDN缓存

浏览器缓存只是为了提升页面再次被访问的速度,而对于提升首次访问的响应能力,通常是采用CDN进行加速。CDN在前端优化过程中起着关键性的作用,理解CDN的工作原理对前端开发人员提升网站性能有着很大的帮助。

什么是CDN?

CDN的全称是Content Delivery Network,即内容分发网络,是指一种通过互联网互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。————维基百科

使用CDN好处?

  • 提升网页加载速度
  • 处理高流量负载
  • 减少带宽消耗
  • 在多台服务器间均衡负载
  • 使你的网站免于DDoS(拒绝服务)的攻击

原理:

用户在通过浏览器访问未使用CDN加速的网站的流程:

图1

  • 用户在浏览器中输入要访问的域名。
  • 浏览器向DNS服务器请求对该域名的解析。
  • DNS服务器返回该域名的IP地址给浏览器。
  • 浏览器使用该IP地址向服务器请求内容。
  • 服务器将用户请求的内容返回给浏览器。

用户在通过浏览器访问使用CDN加速的网站的流程:

图2

  • 用户在浏览器中输入要访问的域名。
  • 浏览器向DNS服务器请求对域名进行解析。由于CDN对域名解析进行了调整,DNS服务器会最终将域名的解析权交给CNAME指向的CDN专用DNS服务器。
  • CDN的DNS服务器将CDN的负载均衡设备IP地址返回给用户。
  • 用户向CDN的负载均衡设备发起内容URL访问请求。
  • 负载均衡设备根据算法为用户选择合适的服务器。
  • 浏览器使用该IP地址向服务器请求内容。
  • 服务器将用户请求的内容返回给浏览器。

总结:

CDN可以加速用户访问速度,减少源站中心负载压力。
CDN建议还是用云服务商的(七牛云之类的),又便宜,又不用管cdn的算法和负载均衡。还能节省服务器成本和维护开支

代理服务器缓存

nginx代理缓存(proxy_cache)

A(用户1)请求服务器资源,
proxy_cache将A从服务器资源上获取到的数据根据预设规则存放到B(内存+磁盘)上留着备用,
C(用户2)请求服务器时,服务器会把缓存的B里的数据直接给C,而不需要再去向服务器去获取。

proxy_cache有几个参数设置要注意下:

  • proxy_cache (开启关闭缓存,需要注意的是从nginx 0.7.66版本开始,proxy_cache机制开启后会检测被代理端的HTTP响应头中的"Cache-Control"、"Expire"头域。
    如,Cache-Control为no-cache时,是不会缓存数据的)

  • proxy_cache_bypass(该参数设定,什么情况下的请求不读取cache而是直接从后端的服务器上获取资源)

  • proxy_cache_path(设置缓存存放路径)

数据库缓存

开启mysql缓存(query cache )

query cache 是用来缓存我们所执行的SELECT语句以及该语句的结果集

参数:

  • query_cache_limit:允许缓存的单条查询结果集的最大容量,默认是1MB,超过此参数设置的查询结果集将不会被缓存
  • query_cache_min_res_unit:设置查询缓存Query Cache每次分配内存的最小空间大小,即每个查询的缓存最小占用的内存空间大小
  • query_cache_size:设置 Query Cache 所使用的内存大小,默认值为0,大小必须是1024的整数倍,如果不是整数倍,MySQL 会自动调整降低最小量以达到1024的倍数
  • query_cache_type:控制 Query Cache 功能的开关 (0,1,2) 1是开启
  • query_cache_wlock_invalidate:控制当有写锁定发生在表上的时刻是否先失效该表相关的Query Cache

外部缓存

Redis缓存

Redis是一款内存高速缓存数据库

作用:提高网站效率,降低数据库的读写次数,引入缓存技术

本质:缓存就是内存中存储数据备份,当数据没有发生本质改变的时候不去数据库中查询,而是去内存中取数据

有两种类别:

  • 页面缓存
  • 数据缓存

Redis有丰富的数据结构,一边运行,一边将数据备份到硬盘,防止断电等意外情况

以上5种大概可以囊括基本的web缓存架构,学会了吗


代码规范

这里写一个简化版,具体的完整版可以去我的github 前端代码规范

一、规范目的

为提高团队协作效率,便于前端后期优化维护,提高代码可读性、可维护性、代码质量。

二、基本准则

  1. 符合web标准,结构表现行为分离,兼容性优良。
  2. 页面性能方面,代码要求简洁明了有序, 尽可能的减小服务器负载,保证最快的解析速度。
  3. 项目的维护和二次开发可能是直接或间接的团队合作,所以创建易维护的代码是一个项目成功与否的关键,易维护的代码意味着具有如下特性:
  • 阅读性好:如良好的注释和命名规范,有文档
  • 具有一致性:看起来如同一个人编写
  • 代码的松耦合,高度模块化:将页面内的元素视为一个个模块,相互独立,尽量避免耦合过高的代码,从html,css,js三个层面都要考虑模块化
  • 严格按照规范编写代码

三、JS规范

1.命名规范
目的

提高代码可预测性和可维护性的方法是使用命名约定,这就意味着采用一致的方法来对变量和函数进行命名

构造函数(类)命名

首字母大写,驼峰式命名。

  let man = new Person();
变量命名

变量名包括全局变量,局部变量,类变量,函数参数
首字母小写,驼峰式(Camel)命名,匈牙利命名
如:checkCount 表示整形的数值

常量

使用全部字母大写,单词间下划线分隔的命名方式。

  let HTML_ENTITY = {};
函数, 函数的参数

使用 Camel 命名法。

  function stringFormat(source) {}
  function hear(theBells) {}
类相关

类:使用 Pascal 命名法(首字母大写的Camel命名法)
类的 方法 / 属性, 使用 Camel 命名法

  function TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
  }

  TextNode.prototype.clone = function () {
    return this;
  };
由多个单词组成的 缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。
  function XMLParser() {}

  function insertHTML(element, html) {}

  let httpRequest = new HTTPRequest();

命名语法

  1. 类名,使用名词
  function Engine(options) {}
  1. 函数名,使用动宾短语
  function getStyle(element) {}
  1. boolean 类型的变量使用 is 或 has 开头
  let isReady = false;
  let hasMoreCommands = false;
  1. Promise 对象用动宾短语的进行时表达。
  let loadingData = ajax.get('url');
  loadingData.then(callback);
例外情况

以根据项目及团队需要,设计出针对项目需要的前缀规范,从而达到团队开发协作便利的目的。
作用域不大临时变量可以简写,比如:str,num,bol,obj,fun,arr
循环变量可以简写,比如:i,j,k等。
某些作为不允许修改值的变量认为是常量,全部字母都大写。例如:COPYRIGHT,PI。常量可以存在于函数中,也可以存在于全局。必须采用全大写的命名,且单词以_分割,常量通常用于ajax请求url,和一些不会改变的数据。

函数命名
  1. 普通函数:首字母小写,驼峰式命名,统一使用动词或者动词+名词形式
  getVersion() // 获得版本号
  submitForm() // 提交表单
  init()  // 初始化
  1. 涉及返回逻辑值的函数可以使用is,has,contains等表示逻辑的词语代替动词
  isObject() // 是否对象
  hasClass('xx') // 有xx对象吗
  containsElment('xx') // 包含xx元素吗
  1. 事件句柄函数,可以在上面的函数名添加handler前缀
  handlerGetVersion()
  handlerSubmitForm()

三、HTML代码规范

谷歌html代码规范

四、CSS代码规范

人们问我最多的问题之一是在CSS类名中“__”和“–”是什么意思?它们的出现是源于BEMNicolas Gallagher…

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由Yandex团队提出的一种前端命名方法论。这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义。BEM命名约定更加严格,而且包含更多的信息,它们用于一个团队开发一个耗时的大项目。

重要的是要注意,我使用的基于BEM的命名方式是经过Nicolas Gallagher修改过的。这篇文章中介绍的这种命名技术并不是原始的BEM,但却是一个我更喜欢的改进版。无论实际使用了什么样的符号,它们其实都是基于同样的BEM原则。

命名约定的模式如下:

  .block{}  
  .block__element{}  
  .block--modifier{}  

.block 代表了更高级别的抽象或组件。
.block__element 代表.block的后代,用于形成一个完整的.block的整体。
.block–modifier代表.block的不同状态或不同版本。
之所以使用两个连字符和下划线而不是一个,是为了让你自己的块可以用单个连字符来界定,如:
在CODE上查看代码片派生到我的代码片

  .site-search{} /* 块 */  
  .site-search__field{} /* 元素 */  
  .site-search--full{} /* 修饰符 */

BEM的关键是光凭名字就可以告诉其他开发者某个标记是用来干什么的。通过浏览HTML代码中的class属性,你就能够明白模块之间是如何关联的:有一些仅仅是组件,有一些则是这些组件的子孙或者是元素,还有一些是组件的其他形态或者是修饰符。我们用一个类比/模型来思考一下下面的这些元素是怎么关联的:

在CODE上查看代码片派生到我的代码片

  .person{}  
  .person__hand{}  
  .person--female{}  
  .person--female__hand{}  
  .person__hand--left{}

顶级块是‘person’,它拥有一些元素,如‘hand’。一个人也会有其他形态,比如女性,这种形态进而也会拥有它自己的元素。下面我们把他们写成‘常规’CSS:

在CODE上查看代码片派生到我的代码片

  .person{}
  .hand{}
  .female{}
  .female-hand{}
  .left-hand{}

这些‘常规’CSS都是有意义的,但是它们之间却有些脱节。就拿.female来说,是指女性人类还是某种雌性的动物?还有.hand,是在说一只钟表的指针(译注:英文中hand有指针的意思)?还是一只正在玩纸牌的手?使用BEM我们可以获得更多的描述和更加清晰的结构,单单通过我们代码中的命名就能知道元素之间的关联。BEM真是强大。

再来看一个之前用‘常规’方式命名的.site-search的例子:

  <form class="site-search  full">  
    <input type="text" class="field">  
    <input type="Submit" value ="Search" class="button">  
  </form>

这些CSS类名真是太不精确了,并不能告诉我们足够的信息。尽管我们可以用它们来完成工作,但它们确实非常含糊不清。用BEM记号法就会是下面这个样子:

  <form class="site-search  site-search--full">  
    <input type="text" class="site-search__field">  
    <input type="Submit" value ="Search" class="site-search__button">  
  </form>

我们能清晰地看到有个叫.site-search的块,他内部是一个叫.site-search__field的元素。并且.site-search还有另外一种形态叫.site-search–full。

我们再来举个例子……

如果你熟悉OOCSS(面向对象CSS),那么你对media对象一定也不陌生。用B__E–M的方式,media对象就会是下面这个样子:

  .media{}  
  .media__img{}  
  .media__img--rev{}  
  .media__body{}

从这种CSS的写法上我们就已经知道.media__img.media__body一定是位于.media内部的,而且.media__img--rev.media__img的另一种形态。仅仅通过CSS选择器的名字我们就能获取到以上全部信息。

BEM的另外一个好处是针对下面这种情况:

  <div class="media">  
    <img src="logo.png" alt="Foo Corp logo" class="img-rev">  
    <div class="body">  
      <h3 class="alpha">Welcome to Foo Corp</h3>  
      <p class="lede">Foo Corp is the best, seriously!</p>  
    </div>  
  </div>

光从上面的代码来看,我们根本不明白.media和.alpha两个class彼此之间是如何相互关联的?同样我们也无从知晓.body和.lede之间,或者.img-rev 和.media之间各是什么关系?从这段HTML(除非你对那个media对象非常了解)中我们也不知道这个组件是由什么组成的和它还有什么其他的形态。如果我们用BEM方式重写这段代码:

  <div class="media">  
    <img src="logo.png" alt="Foo Corp logo" class="media__img--rev">  
    <div class="media__body">  
      <h3 class="alpha">Welcome to Foo Corp</h3>  
      <p class="lede">Foo Corp is the best, seriously!</p>  
    </div>  
  </div>

我们立马就能明白.media是一个块,.media__img--rev是一个加了修饰符的.media__img的变体,它是属于.media的元素。而.media__body是一个尚未被改变过的也是属于.media的元素。所有以上这些信息都通过它们的class名称就能明白,由此看来BEM确实非常实用。

五、GIT规范

master是主分支,开发分支直接从master切出来,这样可以尽可能的简单,避免和第三个分支有关联
通过mr将开发分支合并到master,同时发起Code Review

目录
  1. 分支命名
  2. 注释编写
  3. 提交次数管理
分支命名
  1. 新特性: feature/xxx-saidzhu
  2. 线上紧急bug修复: hotfix/xxx-saidzhu
  3. 测试公用分支: test
注释编写
  1. 如果是新增特性的: Feat:开头
  2. 若果是清理无用代码,文件:Clear:开头
  3. bug修复:Fix:开头
  4. 初始化项目:Init:开头
  5. 重构代码:Refactor:开头
提交次数管理
  1. 一次特性开发竟可能按照开发模块来提交,中间如果一个模块有多次提交,可以通过git rebase 来合并相关的几次提交
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页