1:HTML页面进行重绘和重排
浏览器是如何对页面进行渲染的
当我们在浏览器中打开一个HTML页面时,浏览器的渲染引擎首先会解析标签,渲染成DOM树;
然后解析css样式,构建渲染树;然后从根节点递归调用,计算每一个元素的大小、位置等,并且计算每一个节点的坐标;最后遍历渲染树,绘制每一个节点,这就完成了页面的渲染。
-
所谓重绘就是当元素的外观例如color,background-color等改变时会引起浏览器重新绘制这些元素,使之呈现新的外观。
-
所谓重排(重构/回流)就是当元素的大小、位置等改变或显示隐藏从而引起浏览器重新构建。
-
重绘不一定引起重排,但重排一定会引起重绘。
-
频繁的重绘重排会损耗性能,导致浏览器卡顿,所以我们要尽量避免频繁的操作DOM
2:网页验证码的作用
-
常用:短信验证码,滑块验证、拼图验证、输入图片文字验证等
-
作用:1、防止攻击者恶意登录注册
2、防止病毒或其他软件自动登录或注册
3、短信验证码可验证用户的合法性
3、前端工程化
- 如何进行高效的多人协作?
- 如何保证项目的可维护性?
- 如何提高项目的开发质量?
- 如何降低项目生产的风险?
- …
前端工程化是使用软件工程的技术和方法来进行前端的开发流程、技术、工具、经验等规范化、标准化,其主要目的*为了提高效率和降低成本,即提高开发过程中的开发效率,减少不必要的重复工作时间*,而前端工程本质上是软件工程的一种,因此我们应该从软件工程的角度来研究前端工程。
"前端工程化"里面的工程指软件工程,和我们一般说的工程是两个完全不同的概念。
- 工程是个很泛泛的概念,甚至可以认为建了一个git仓库就相对于新建了一个工程;
- 软件工程的定义是: “应用计算机科学理论和技术以及工程管理原则和方法,按预算和进度,实现满足用户要求的软件产品的定义、开发、和维护的工程或进行研究的学科”(GB/T11457-2006《信息技术 软件工程术语》)。
如何做"前端工程化"?
前端工程化就是为了让前端开发能够“自成体系”,个人认为主要应该从模块化、组件化、规范化、自动化四个方面思考。
模块化
简单来说,模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。
-
JS的模块化
在ES6之前,JavaScript一直没有模块系统,这对开发大型复杂的前端工程造成了巨大的障碍。对此社区制定了一些模块加载方案,如CommonJS、AMD和CMD等。
现在ES6已经在语言层面上规定了模块系统,完全可以取代现有的CommonJS和AMD规范,而且使用起来相当简洁,并且有静态加载的特性。
- 用++Webpack + Babel++将所有模块打包成一个文件同步加载,也可以搭乘多个chunk异步加载;
- 用++System+Babel++主要是分模块异步加载;
- 用浏览器的
组件化
从UI拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元,我们称之为组件。
组件化≠模块化。模块化只是在文件层面上,对代码或资源的拆分;而组件化是在设计层面上,对UI(用户界面)的拆分。
其实,组件化更重要是一种分治思想。
Keep Simple. Everything can be a component.
页面上所有的东西都是组件。页面是个大型组件,可以拆成若干个中型组件,然后中型组件还可以再拆,拆成若干个小型组件,小型组件也可以再拆,直到拆成DOM元素为止。DOM元素可以看成是浏览器自身的组件,作为组件的基本单元。
传统前端框架/类库的思想是先组织DOM,然后把某些可复用的逻辑封装成组件来操作DOM,是DOM优先;而组件化框架/类库的思想是先来构思组件,然后用DOM这种基本单元结合相应逻辑来实现组件,是组件优先。这是两者本质的区别。
其次,组件化实际上是一种按照模板(HTML)+样式(CSS)+逻辑(JS)三位一体的形式对面向对象的进一步抽象。
所以我们除了封装组件本身,还要合理处理组件之间的关系,比如 (逻辑)继承、(样式)扩展、(模板)嵌套和包含等,这些关系都可以归为依赖。
目前市面上的组件化框架很多,主要的有Vue、React、Angular。Vue文档中的对比其他框架一文已经讲得很详细了。
规范化
规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。
比如:
-
目录结构的制定
目录结构的合理设定,能为项目带来很多优点:
- 有助于提高项目的逻辑结构合理性;
- 对应扩展和合作;
- 方便资源的统一定位管理。
-
编码规范
制定一套良好的编码规范可以增强团队开发协作、提高代码质量。
推荐参考凹凸实验室打造的前端代码规范。编码规范包括
-
HTML规范。
基于 W3C、苹果开发者 等官方文档,并结合团队业务和开发过程中总结的规范约定,让页面HTML代码更具语义性。
-
CSS规范。
统一规范团队 CSS 代码书写风格和使用 CSS 预编译语言语法风格,提供常用媒体查询语句和浏览器私有属性引用,并从业务层面统一规范常用模块的引用。
-
JS规范。
统一规范团队 CSS 代码书写风格和使用 CSS 预编译语言语法风格,提供常用媒体查询语句和浏览器私有属性引用,并从业务层面统一规范常用模块的引用。
-
图片规范。
了解各种图片格式特性,根据特性制定图片规范,包括但不限于图片的质量约定、图片引入方式、图片合并处理等,旨在从图片层面优化页面性能。
-
命名规范。
从 目录、图片、HTML/CSS文件、ClassName 的命名等层面约定规范团队的命名习惯,增强团队代码的可读性。
-
-
前后端接口规范
“基于 Ajax 带来的 SPA 时代”,这种模式下,前后端的分工非常清晰,前后端的关键协作点是 Ajax 接口,引发一个重要问题:前后端的对接界面双方却关注甚少,没有任何接口约定规范情况下各自撸起袖子就是干,导致我们在产品项目开发过程中,前后端的接口联调对接工作量占比在30%-50%左右,甚至会更高。往往前后端接口联调对接及系统间的联调对接都是整个产品项目研发的软肋。
接口规范主要初衷就是规范约定先行,尽量避免沟通联调产生的不必要的问题,让大家身心愉快地专注于各自擅长的领域。
那么,对于这一SPA阶段,前后端分离有几个重要的关注挑战:
-
职责分离
- 前后端仅仅通过异步接口(AJAX/JSONP)来编程;
- 前后端都各自有自己的开发流程,构建工具,测试集合;
- 关注点分离,前后端变得相对独立并松耦合。
后端 前端 提供数据 接收数据,返回数据 处理业务逻辑 处理渲染逻辑 -
规范原则
- 接口返回数据即显示,前端仅做渲染逻辑处理;
- 渲染逻辑禁止跨多个接口调用;
- 前端关注交互、渲染逻辑,尽量避免业务逻辑处理的出现;
- 请求响应传输数据格式:JSON,JSON数据尽量简单轻量,避免多级JSON的出现;
-
响应格式
- 响应基本格式及处理状态值的规范。
- 基本响应格式
- 列表响应格式
- 特殊内容
- 下拉框、复选框、单选框统一由后端逻辑判定选中返回给前端展示;
- 关于Boolean类型,JSON数据传输中一律使用1/0来标示,1为是/True,0为否/False
- 关于日期类型,JSON数据传输中一律使用字符串,具体日期格式因业务而定;
- 响应基本格式及处理状态值的规范。
-
-
文档规范
-
组件管理
-
git分支管理
-
commit描述规范
-
视觉图标规范
-
…
自动化
前端工程化的很多脏活累活都应该交给自动化工具来完成。需要秉持的一个理念是:
任何简单机械的重复劳动都应该让机器去完成。
- 图标合并
- 持续集成
- 自动化构建
- 自动化部署
- 自动化测试
4、HTTP请求
> * 浏览器对网址进行DNS域名解析,得到对应的IP地址
> * 根据这个IP地址,找到对应的服务器,发起TCP的三次握手
> * 建立TCP连接后发起http请求
> * 服务器端响应http请求,浏览器得到html代码
> * 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)
> * 浏览器对页面进行渲染呈现给用户
> * 服务器关闭TCP连接
- 域名解析:采用递归查询的方式。
- 首先会搜索浏览器自身的DNS缓存
- 没有找到,那么浏览器会搜索系统自身的DNS缓存
- 没有找到,那么尝试从hosts文件里面去找
- 就递归去域名服务器查找
- http缓存:只能缓存 get 方式请求的资源。可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
- TCP连接的三次握手:
- 客户端发送请求建立连接,请求报文段。
- 服务器收到请求,发送同意并请求与客户端建立连接
- 客户端收到请求,发送同意与服务器建立连接
- TCP断开连接的四次分手
- 客户端发送断开请求
- 服务器收到断开请求,发送同意断开连接的请求
- 服务器发送请求断开连接
- 客户端收到,发送同意断开连接
5、跨域
-
同源策略:为了网络安全起见,浏览器设置了一个同源策略,规定只有协议(https),域名(192.168.0.35),端口号(8082)全部相同,就叫做同源。因此当访问和被访问的资源不同源时,就会出现跨域。
http://192.168.0.35:8082/#/pages/home/index
-
解决跨域的方法
1、JSONP --在页面中通过
script
标签加载资源,是不存在跨域的问题,基于这一原理,我们可以通过动态的创建过script
标签,然后src
赋值一个带参的url,进而实现跨域,也叫jsonp跨域。
JSONP由两部分组成,回调函数和数据
优点:
(1)兼容性好,在多古老的浏览器都能运行。
(2)能直接访问响应文本,支持在浏览器与服务器之间双向通信。
缺点:
(1)只支持GET请求,不支持POST请求;
(2)不够安全。因为JSONP是从其他域中加载代码执行,如果其他域不安全,可能会在响应中带有恶意代码。
(3)不容易确认请求是否失败。$.ajax({ url:'http:/www.monkey.com/admin/getUser', dataType:"jsonp", jsonp: "callback",//请求时路径参数名 jsonpCallback:"callback",//设置后端返回函数名 success:function(data){//回调函数 console.log(data); } }); $.get('http:/www.monkey.com/admin/getUser', {各种数据}, function(data) { console.log(data); }, 'jsonp');
2、CORS – 跨站资源共享。浏览器会自动进行CORS通信,实现CORS通信的关键是后端,只要后端设置Access-Control-Allow-Origin 就可以解决
3、webSockets – 不受同源策略影响。原理是因为它不使用HTTP协议,而使用一种自定义的协议,专门为快速传输小数据设计。
4、Nginx – 代理跨域。反向代理跨域。
6、性能优化
首页加载慢的优化
-
原因
-
首页加载图片过多
-
通过懒加载的方式来减少首屏图片的加载量。懒加载原理就是监听滚动条事件,如果(滚动条距离浏览器顶部的高度 === 图片距离顶部的高度),那么就将 data-src 的值赋值到 src 上
-
对于小图标可以采用 字体图标;对于小图片可以采用雪碧图的方式解决
-
-
首页的请求量过多
- 可以通过减少资源的请求量。webpack合并js、css文件
- 对引入的UI组件库,采用按需引入的方式;
- vue路由懒加载
-
首页请求的静态资源(HTML、CSS、JS、图片…)过大
-
图片的优化
图片的优化,也是从两个方面来考虑:太多 和 太大。
可以通过懒加载减少图片的请求,或者通过雪碧图来合并图片,以及将小图转化成 base64 的格式,来解决多的问题。
图片大的问题,可以通过自动化压缩工具来压缩图片,或者使用 WebP 格式的图片。
webpack的打包优化
Webpack 打包优化,也是从两个方面来考虑:太多 和 太大。
- 可以通过设置 mode = production 来默认实现 Webpack 对代码的混淆和压缩,从而最大程度的减少代码体积
- 使用 Webpack + dynamic import 并结合路由的入口文件做拆包处理。
- 并且可以设定一些打包策略,并配合网络缓存做最终的加载性能优化。
实现CDN加速
CDN 服务器主要是用来放静态资源的服务器,可以用来加速静态资源的下载
CDN 之所以能够加速,是因为会在很多地方都部署 CDN 服务器,如果用户需要下载静态资源,会自动选择最近的节点下载
同时由于 CDN 服务器的地址一般都跟主服务器的地址不同,所以可以破除浏览器对同一个域名发送请求的限制
渲染优化、大量数据不卡顿
- 可以使用 document.createDocumentFragment 创建虚拟节点,从而避免引起没有必要的渲染
- 当所有的 li 都创建完毕后,一次性把虚拟节点里的 li 标签全部渲染出来
- 可以采取分段渲染的方式,比如一次只渲染一屏的数据
- 最后使用 window.requestAnimationFrame 来逐帧渲染
创建一个新项目时,要搭建一个开发框架,所需要考虑的点有哪些?
语言框架的选型,开发人员对技术的熟悉程度,
公共组件的方案,通用布局/面包屑方案,
代码规范和审查方案,项目打包配置及自动化部署方案等
css性能优化-GPU加速
WEB应用常见15种安全漏洞
-
SQL注入:通过给 web 应用接口传入一些特殊字符,达到欺骗服务器执行恶意的 SQL 命令。
解决:不信任任何外部输入,执行严格的输入验证,使用正规表达式,严格检查输入的类型、长度和内容
-
跨站脚本攻击(XSS):攻击者通过在目标网站上注入恶意脚本并运行,获取用户的敏感信息。
解决:渲染前端页面(不管是客户端渲染还是服务器端渲染)或者动态插入 HTML 片段时,任何数据都不可信任,都要先做 HTML 过滤,然后再渲染。
-
恶意文件上传:通过修改上传功能程序的参数内容,从而达到上传恶意文件的目的
解决:对上传文件类型、大小检查
-
暴力密码破解:弱密码(Weak Password)很容易被别人(对你很了解的人等)猜到或被破解工具暴力破解。
解决:限制密码复杂度,限制密码输入错误次数
-
个人信息修改、密码修改、手机号修改需要加验证码验证;
-
恶意注册、注册前加验证
tab切换,接口反应慢,造成渲染错乱
this.req.abort() //tab切换时取消上次接口请求
disable列表项的方案 - 不通过
防抖/节流方案 - 不通过(无法完全避免)
如果使用ajax/axios,发起请求时可直接取消上一次未完成的请求 - 得分
临时记录最后一次的id,要求服务器返回时携带id,对比选择后渲染 - 得分
临时记录最后一次的id,闭包内存放每次请求的id,对比选择后渲染 - 通过
上一个回答,如果能够整合成一个高阶函数,与业务分离,单独包装某个请求就可以实现该逻辑 - 最佳
渲染大量图片
所有图片先提供占位图 - 得分
懒加载思想 - 得分
使用队列的方式 - 得分
通过信号量的机制,结合队列。例如设置可用资源数为10,则保证同一时刻,只有10张图片正在请求,其它图片处于loading状态,任意图片请求完成,才释放资源,从队列选取下一张图片进行加载 - 通过
无线滚动列表(海量数据列表)的优化方案
防抖/数据懒加载 - 不得分(没审清楚题意)
只展示可视区域的内容,在列表项移动到不可见的区域时移除节点 - 得分
移除的节点,通过占位元素撑起来,保持滚动条高度相对不变 - 得分
通过计算列表的项数和每项高度,使所有列表项通过绝对定位展现,保持滚动条高度相对不变 - 通过
能够给出每个列表项高度不固定,且会动态改变的方案 - 最佳。
实现虚拟列表就是处理滚动条滚动后的可见区域的变更,其中具体步骤如下:
- 计算当前可见区域起始数据的 startIndex
- 计算当前可见区域结束数据的 endIndex
- 计算当前可见区域的数据,并渲染到页面中
- 计算 startIndex 对应的数据在整个列表中的偏移位置 startOffset,并设置到列表上
创建一个新项目时,要搭建一个开发框架,所需要考虑的点有哪些?
语言框架的选型,开发人员对技术的熟悉程度,
公共组件的方案,通用布局/面包屑方案,
代码规范和审查方案,项目打包配置及自动化部署方案等
浏览器兼容问题
- 不同浏览器对HTML标记所具有的内外边距属性具有不同的定义。
因此如果想消除这种差距,应该在相应的CSS部分加入以下CSS代码:
*{margin:0px;padding:0px;}
借于此,所有标记的内外边距被统一起来。
2.优先级问题:
对于同一标记属性所给定的值,有不同的优先级。其中优先级最高的是内联代码,其实是页内CSS,接下来是浏览器默认设置,最后才是外部CSS所做的限制。
3.Margin不一致的问题:
当有多张图片需要排在一行时,我们通常使用“Float:Left”来实现,这样一来,浏览器就存在兼容性问题。导致图片与后面的内容存在margin不一致的问题。对此一种解决方法就是给图片添加“Display:inline”项即可。
4.DIV居中问题:
通常我们会利用“vertical-align:middle”来实现,这对于搜狗浏览器来说,是正常的,但是对于IE浏览器来说,却并没有效果。对此,一种较好的解决方法是:将文字的行高设置与DIV一样时即可解决问题。