首页
学习
活动
专区
工具
TVP
发布

现代前端技术解析:前端项目与技术实践

前端项目与技术实践

前端开发规范

HTML规范

head内容

​ head中必须定义title、keyword、description,保证基本的SEO页面关键字和内容描述。移动端页面head要添加viewport控制页面不缩放,有利于提高页面渲染性能。建议在页面<head>加上基本的社交RICH化消息,保证网页地址分享后能够显示缩放图、图标和描述等。

<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta itemprop="name" content="页面标题">
<meta name="description" itemprop="description" content="页面内容描述">
<meta itemprop="image" content="http://xxx.com/logo.png">

img的alt属性

<img>元素上加alt属性,用利于页面搜索引擎优化,对于盲人用户和图像加载失败的提示很实用(支持无障碍阅读)

<img src="banner.jpg" alt="宣传图片">

label的for属性

label的for属性或者将对应控件放在label标签内部,这样在点击label时,同时会关联到对应的input或textarea上选中,增加了输入的响应区域。

<label for="blue">蓝色</label><input type="radio" id="blue" name="color" value="#00f">
<label><input type="radio" name="color" value="#f00">红色</label>

css规范

  • 书写CSS样式不能用id选择器,因为id选择器很难复用;
  • 如果属性值为0,不需要为0加单位;
  • 先写元素的布局属性position、display、float、overflow等,再写元素的内容属性color、font、text-align等
  • 多种浏览器兼容,先写私有属性、后写标准属性 .ui-news { -webkit-box-shadow: 1px 1px 5px; -moz-box-shadow: 1px 1px 5px; -ms-box-shadow: 1px 1px 5px; -o-box-shadow: 1px 1px 5px; box-shadow: 1px 1px 5px; }

JavaScript规范

条件判断

不要直接使用undefined进行变量判断。

// 不推荐
if(name == undefined) {return false;}
// 推荐
if(typeof person === 'undefined') {return false;}

数组拷贝

let ary = [1, {a: 2}];
let ary2 = [...ary];
let ary3 = {};
Object.assign(ary3, ary);
ary[1].a = 3;
ary2[1].a; // 3
ary3[1].a; // 3

注意:都是浅拷贝!!

数组遍历使用for…of,对象遍历使用for…in

let ary = ['a', 'b', 'c'];
let obj = { a: 1, b: 2};
for(let item of ary) {
  console.log(item);
}
for(let key in obj) {
  console.log(`${key}, ${obj[key]}`)
}

前端防御性编程规范

防御性编程是指通过检测任何可能存在的逻辑异常问题的代码实现,提高脚本执行过程健壮性的一种编程手段。

// 不推荐
t = data.userInfo.name;
// 推荐
t = data && data.userInfo && data.userInfo.name || 'ligang';

通过&&或者||进行检测,这也是函数式编程所提倡的!

前端组件规范

所谓的组件通常是指采用代码管理中的分治思想,将复杂的项目代码结构拆分成多个独立、简单、解耦合的结构或文件的形式进行分开管理,达到让项目代码和模块更加清晰的目的,而组件规范则是我们进行拆分、组织、管理项目代码方法的一种约定。不同的是,开发规范关注文件内部代码级别的一致性,组件规范则更关注项目中业务功能模块内容组织的一致性。任何一个独立的功能模块之间都应该是无耦合并能和其他模块很好对接和组合!

UI组件规范

(1)UI层风格统一化,相同功能的模块在相同场景下结构层和表现层应该一致;(2)增加UI层复用性;(3)更符合用户的体验习惯;(4)增加了开发规范的统一性。

模块化规范

JavaScript文件之间互相依赖引用的一种通用语法约定,即按照一定规范写JavaScript,方便被其他JavaScript文件引用。主要包括AMD(Asynchronous Module Definition,异步模块定义)、CMD(Common Module Definition,通用模块定义)、CommonJS、import/export等。参考:前端模块系统

项目组件化设计规范

为了实现对复杂的项目进行管理,我们通常使用组件,目前实现组件化的方案也越来越多:Web Component组件化、MVVM框架组件化(通常,将页面中的模块按照元素来划分,并将模块相关的描述语法、CSS样式、执行脚本放在同一个文件里进行引用)、基于Virtual DOM框架的组件化、直接基于目录管理的组件化等。

自动化构建

自动化构建时基于项目代码文件级的分析处理。

注意,为了保证首屏加载的资源最小化,非首屏内容希望通过JavaScript来异步渲染,这就需要构建工具能将非首屏的组件打包成异步资源,以按需或异步的方式加载。在开发中,我们通常不希望关注异步与同步组件的区别,所以通过将异步组件放在异步的目录里进行单独打包或者加入特殊的标识。

以require的引用方式为例,了解一下JavaScript组件模块文件的依赖分析过程:

  1. 从入口模块开始分析require函数调用依赖;
  2. 根据依赖生成JavaScript AST(Abstract Syntax Tree,抽象语法树,将JavaScript代码映射成一个树形结构的JSON对象树)
  3. 根据AST找到每个模块的模块名;
  4. 得到每个模块的依赖关系,生成一个依赖字典;
  5. 根据模块化引用机制包装每个模块,传入依赖字典以及import或require函数,生成执行的JavaScript代码。

前端性能优化

用户获取页面数据或执行某个页面动作的一个实时性指标,一般以用户希望获取数据的操作到用户实际获得数据的时间间隔来衡量。用户的等待延迟可分为两部分:可控等待延时(资源大小、HTTP数量等)和不可控等待延时(鼠标点击延时、CPU计算延时、ISP网络传输延时等)

performance Timing API

用于记录页面加载和解析过程中关键时间点的机制,它可以详细记录每个页面资源从开始加载到解析完成这一过程中具体操作发生的时间点。(图片引自:https://w3c.github.io/navigation-timing/

// 加载时间耗时(整体)
performance.timing.loadEventEnd - performance.timing.navigationStart;
// 针对单个资源
let p = performance.getEntriesByName("https://www.baidu.com/");
p[0].responseEnd - p[0].requestStart; //204.175 Request请求耗时
p[0].domComplete - p[0].domInteractive; // 490.56999999999994 解析DOM树耗时
p[0].loadEventEnd - p[0].loadEventStart; // 35.955000000000155 Load事件消耗

参考资料:https://www.w3.org/TR/2017/CR-resource-timing-1-20170330/

Profile工具

Profile用来测试页面脚本运行时系统内存和CPU资源占用情况的API,可以获得如下几个信息:

  • 分析页面脚本执行过程中最消耗资源的操作;
  • 记录页面脚本执行过程中JavaScript对象消耗的内存与堆栈的使用情况;
  • 检测页面脚本执行过程中CPU占用情况。
console.profile();
document.querySelector('#content').innerHTML = '棒棒';
calc();
function calc() {
  let result = null;
  for(let i = 0; i < 100000; i++) {
    result += i;
  }
  return result;
}
console.profileEnd();

资源加载时序图

通过时序图可以确保文件加载顺序的情况,查看是否存在十分耗时的阻塞页面展示的资源加载。

桌面浏览器前端优化策略

  • 避免页面中空的href和src:浏览器在渲染的过程中仍会将href属性或src属性中的空内容进行加载,直至失败,这样会阻塞页面中其他资源的下载进程;
  • 为HTML指定Cache-Control或Expires:在页面Cache-Control或Expires头部有效时,浏览器将直接从缓存中读取内容,不向服务器发送请求;
  • 减少页面重定向:一次重定向大约需要600毫秒的时间开销;
  • 将静态资源分域存放来增加并行下载数:同一时刻向同一域名请求文件的并行下载数是有限的,因此可以使用多个域名的主机来存放不同的静态资源,同时可以隔离Cookie,减少了请求头大小
  • 使用CDN Combo下载传输内容:复用HTTP连接,将多个文件请求打包成一个文件的形式来返回,以减少HTTP请求数; <script src="//cdn.xxx.com/path/a.js,b.js,c.js"></script>
  • 缩小favicon.ico并缓存:一般Web应用的favicon.ico是很少改变的;
  • 推荐使用异步JavaScript资源:使用async时,加载和渲染后续文档元素的过程和main.js的加载和执行是并行的;使用defer时,加载后续文档元素的过程和面.js的加载是并行的,但是main.js的执行要在页面所有元素解析完成之后才开始执行; <script src="main.js" defer></script> <script src="main.js" async></script>
  • 避免使用CSS import引用加载CSS:因为这样会增加CSS资源加载的关键路径长度,代用@import的CSS样式需要在CSS文件串行解析到@import时才会加载另外的CSS文件,大大延后CSS渲染完成的时间;
  • CSS放到<head>中,JavaScript放到<HTML>文档底部:这样可以尽早完成页面渲染,同时防止JavaScript的加载和解析执行对页面渲染造成阻塞;
  • 尽量避免使用<table><iframe>等慢元素:<table>内容的渲染是将table的DOM渲染树全部生成完并一次性绘制到页面上;iframe内资源的下载进程会阻塞父页面静态资源的下载与CSS及HTML DOM的解析,尽量使用异步的方式动态添加iframe;

移动端浏览器前端优化策略

  • 确保首屏内容最小化:首屏所有资源大小不超过1MB;
  • inline首屏必备的CSS和JavaScript:将首屏加载的CSS和JavaScript内联到页面中;
  • meta dns prefetch 设置DNS预解析:让浏览器提前解析获取静态资源的主机IP; <meta http-equiv="x-dns-prefetch-control" content="on"> <link rel="dns-prefetch" href="//cdn.domain.com">
  • **合理利用MTU策略:**TCP网络传输最大传输单位(Maximum Transmission Unit,MTU)为1500B,即一个RTT(Round-Trip Time,网络请求往返时间)内可以传输的数据量最大为1500字节,因此尽量保证页面HTML内容控制在1KB内;
  • 合理使用base64内嵌图片:较小的图片可以使用base64嵌入到HTML页面或CSS中,大于2KB不推荐使用base64; .class-name { background-image: url('data:image/png;base64,iVboR...'); }
  • 尽量使用事件代理,避免直接事件绑定: 使用事件代理可以避免对每个元素都进行绑定,并且可以避免出现内存泄漏及需要动态添加元素的事件绑定问题;
  • **使用touchstart代替click:**touchstart事件和click事件触发时间之间存在300毫秒的延时;
  • 避免touchmove、scroll连续事件处理:应该使用节流函数,可参照debounce与throttle区别
  • 不要滥用float:使用float的元素布局计算比较消耗性能;
  • **尝试使用SPDY和HTTP2:**SPDY基于TCP,对HTTP的增强版(多路复用,请求优先级,HTTP报头压缩);

前端用户数据分析

因为目前从事的公司Ptmind就是在做用户数据分析,自己也是Ptengine采集器的主力,所以后续有时间单独进行描述!

前端日志上报

浏览器提供了try…catch和window.onerror两种机制来帮助我们获取用户页面的脚本错误信息。window.onerrorl可捕获脚本语法错误和运行时错误,但对于报错的JavaScript和HTML不在同一域名下,获得的错误都是script error,可以通过<scritp src="//otherDomain.com/main.js" crossorigin></script>来获取具体信息。

window.onerror = function(messageOrEvent, source, lineno, colno, error) {
    console.log(messageOrEvent, source, lineno, colno, error);
    return true;    // 彻底忽略所有错误
};

捕获到错误后,我们需要根据一定的概率进行上报(如果将所有错误进行上报会占用日志收集服务器的很多资源和流量),通常我们可以进行封装log.log,在开发环境中直接使用console.log/error,在生产环境使用XMLHttpRequest。总之,我们需要根据实际情况指定,千万不可过度设计

前端搜索引擎优化

  • 一定要定义title、keywords、description:多个title值使用分隔符(“_”、“-”、“ ”、“,”),确保每个页面的title是对一无二的;
  • 每个页面都有一个唯一的H1,同时所有的img都有alt属性:<h1>作为页面最高层的标题通常容易被搜索引擎收录;
  • 如果URL发生改变,一定要使旧地址301指向新的页面,否则搜索引擎会把这个当成死链处理
  • canonical:通常会将下面当做3个地址当做3个页面 //:domain.com/index.html //:domain.com/index.html?from=123 //:domain.com/index.html?form=456 可以在<head>上加上canonical声明,告诉浏览器将按照这个href进行收录 <link rel="cononical" href="//:domain.com/index.html" />
  • 将robots.txt放置站点根目录,禁止抓取网站某些内容
  • sitemap.html或sitemap.xml列出所有URL,便于搜索引擎获取

前端协作

明确、合理、可行、性价比、风险。做团队技术驱动者和突破者!

下一篇
举报
领券