1.页面的重构和回流
重构:
改变每个元素的外观时所触发的浏览器的行为,如颜色、背景等样式发生改变而进行的重新构造新外观的行为。重构不会引发页面的重新布局,不一定伴随着回流。
重构时需要注意:
页面的健壮性:在页面排版时需要考虑数据极多或者极少的情况。
页面的扩展性:要考虑未来添加子模块或兄弟模块的状态,为将来留好css、html扩展的出入口。在将来添加模块的时候,尽可能少的去动原来的html结构,使html易于扩展,尽可能少的去修改css,使css能够继承可复用。一般的处理就是多套一层div,或其它解决办法。
页面的复用性:建议把表现形式的样式放在一个class中,物理属性放在一个class中。
页面重构通常包括:
(1)table布局改为div+css
(2)使网站前端兼容现代浏览器
(3)对移动平台的优化
(4)针对SEO进行优化
(5)减少代码间的耦合,让代码保持弹性
(6)严格按照规范编写代码
(7)设计可扩展的API
(8)替换旧的框架、语言
(9)增强用户体验
(10)针对速度进行优化
(11)压缩JS、css、image等前端资源(通常是由服务器来解决)
(12)采用CDN来加速资源加载
(13)对于JS DOM的优化
(14)HTTP服务器的文件缓存
回流:
浏览器为了进行重新渲染页面而进行的重新计算元素几何大小和位置,回流可以理解为渲染树重新进行计算,一般最好触发元素的重构避免元素的回流。比如通过添加class来添加css样式,而不是直接在DOM上设置,当需要操作某一块元素的时候,最好使其脱离文档流,这样就不会引起回流了,比如设置position:absolute或者fixed,或者display:none,等操作结束后在显示。
2.移动端的优化
(此处参考浅谈前端性能优化(移动端))
网络加载类
(1)首屏数据请求提前,避免JavaScript文件加载后才请求渲染
为了进一步提示页面加载速度,可以考虑将页面的数据请求尽可能提前,避免在JavaScript文件加载完成后才去请求数据。通常数据请求是页面内容渲染中关键路径最长的部分,而且不能并行,所以如果数据请求能提前的话,可以极大程度上缩短页面内容的渲染完成时间。
(2)首屏加载和按需加载,非首屏内容滚屏加载,保证首屏内容最小化
由于移动端网络相对较慢,网络资源有限,因此为了保证尽快完成页面内容的加载,需要保证首屏加载资源的最小化,非首屏的内容使用滚动的方式异步加载。一般推荐移动端页面首屏数据展示延迟不超过3秒。
(3)模块化资源并行下载
主要指模块化JavaScript资源的异步加载,例如AMD的异步模块,使用并行的加载方式能够缩短多个文件资源的加载时间。
(4)inline首屏必备的CSS和JavaScript
通常为了在HTML加载完成时能使浏览器中有基本的样式,需要将页面渲染时必备的CSS和JS通过script或style的方式内联到页面中,避免页面HTML载入完成到页面内容展示这段过程中页面出现空白。
(5)meta dns prefetch设置DNS预解析
设置文件资源的DNS预解析,能让浏览器提前解析获取静态资源的主机IP,避免等到请求的时候才发起DNS解析。
<meta http-equiv='x-dns-prefetch-control' content='on'>
<link rel="dns-prefetch" href="//x.autoimg.cn">
(6)资源预加载
首屏加载完成后可能会使用的资源,我们可以用 link标签声明特定文件的预加载
<link rel='subresource' href='main.css'>
<link rel='prefetch' href='secondary.js'>
注意:只有可缓存的资源才进行预加载,否则浪费资源!
(7)Pre render预渲染
预渲染意味着我们提前加载好用户即将访问的下一个页面,否则进行预渲染这个页面将浪费资源,慎用!
<link rel='prerender' href='//j.autohome.com.cn'>
(8)合理利用MTU策略
通常情况下,TCP网络传输的最大传输单元(MTU)为1500B,即一个RTT(Round-Trip Time,网络请求返回时间)内可以传输的数据量最大为1500字节(为什么以太网mtu值被设定为1500 - 知乎)。因此在前后端分离的开发模式中,尽量保证页面的HTML内容在1KB以内,这样整个HTML内容的请求就可以在一个RTT内完成,最大限度的提高了HTML载入速度。
缓存
(1)合理利用浏览器缓存
除了Cache-Control、Expires、Etag和Last-Modified来设置HTTP缓存外,在移动端还可以使用localstorage等来保存ajax返回的数据,或者使用localstorage保存CSS或JS等静态资源,实现移动端的离线应用,尽可能的减少网络请求,保证静态资源内容的快速加载。
(2)静态资源离线方案
对于移动端或者混合应用,可以设置离线文件或离线包机制让静态资源请求从本地读取,加快资源载入速度,并实现离线更新。这块推荐叶小钗大神的 前端优化带来的思考,浅谈前端工程化 。
(3)尝试使用 AMP HTML
AMP HTML 可以作为优化前端页面性能的一个解决方案,使用AMP Component中的元素来代替原始页面元素进行直接渲染[译]关于谷歌的AMP,你需要知道这些 。
图片类
(1)图片压缩处理
移动端通常要保证页面中一切用到的图片都是经过压缩优化处理,而不是以原图的形式直接使用的,因为那样很消耗流量,并且加载时间更长。
(2)使用较小的图片,合理使用base64内嵌图片
在页面使用的背景图片不多且比较小的情况下,可以把图片转成base64编码嵌入到html页面或者CSS文件中,这样可以减少页面的HTTP请求数。需要注意的是,要保证图片较小,一般超过5kb的就不推荐base64嵌入显示了(前端开发中,使用base64图片的弊端是什么? - 知乎)。
(3)使用更高压缩比格式的图片
使用具有较高压缩比格式的图片,如webp等。在同等图片画质的情况下,高压缩比格式的图片体积更小,能够更快的完成文件传输,节省网站流量。
(4)图片懒加载
为了保证页面内容最小化,加速页面渲染,尽可能节省首屏网络流量,页面中的图片资源推荐使用懒加载实现,在页面滚动时动态载入图片。
(5)使用Media Query 或者 srcset 根据不同屏幕加载不同大小的图片
针对不同屏幕尺寸和分辨率,输出不同大小的图片或者背景图能保证用户体验不降低的前提下节省网络流量,加快部分机型图片载入速度。
(6)使用iconfont代替图片图标
iconfont体积较小而且是矢量图,因此缩放不会失真,还可以方便修改图片大小和呈现的颜色,但是需要注意iconfont引用不同webfont格式会有兼容问题。
(7)定义图片大小限制
加载单张图片不建议超过30KB,避免大图片加载时间过长而阻塞页面其他资源的下载。如果用户上传的图片过大,建议设置限制。
脚本类
(1)尽量使用id选择器
选择页面DOM元素时尽量使用id选择器,因为id选择器速度最快。
(2)合理的缓存dom对象
对于需要重复使用的dom对象,要优先设置缓存变量,避免每次使用时都要从整个dom树重新查找。
// 不推荐
$("#mod .active").removeClass('active');
$("#mod .not-active").addClass("active");
// 推荐
const $mod = $("#mod");
$mod.find(".active").removeClass("active")
$mod.find(".not-active").addClass("active")
(3)页面元素尽量使用事件代理,避免事件直接绑定
使用事件代理可以避免对每个元素都进行绑定。并且可以避免出现内存泄漏以及需要动态添加元素的事件绑定问题
// 不推荐
$(".btn").click( _ => console.log("hello") )
// 推荐
$(document).on("click", ".btn", _ => console.log("world"))
(4)使用touch代替click
由于移动端屏幕的设计,touch事件和click事件触发之间存在300ms延迟,所以在页面没有touchmove实现滚动处理的情况,可以用touchstart代替元素的click事件,加快页面点击的响应速度,提高用户体验。但同时也需要注意页面重叠元素touch动作的点透问题。
// 不推荐
$("body").on("click",".btn",function(){ console.log(this) });
// 推荐
$("body").on("tap",".btn",function(){ console.log(this) });
// tap为zepto用touch事件封装的
(5)避免touchmove,scroll等连续事件处理
需要对这类高频触发回调的事件设置函数节流(throttle | debounce),避免频繁的事件调用导致移动端页面卡顿。
(6)避免使用eval、with,使用join代替连接符+,推荐使用ES6的模板字符串
基本的安全脚本编写问题,尽可能使用高效率的特性来完成这些操作,避免不规范或者不安全的写法。
(7)尽量使用ES6+的特性来编程
ES6+在一定程度上更高效,在chrome59版本对ES6做了深度优化之后,很多特性速度提升了80%左右,这也是未来规范的需要。
渲染类
(1)使用viewport固定屏幕渲染,可以加速页面渲染内容
一般认为,在移动端设置viewport可以加速页面的渲染,同时可以避免缩放导致页面重排重绘。
// 利用meta标签对viewport进行控制
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
(2)避免各种形式重排(reflow)重绘(redraw)
页面的重排重绘很耗性能,所以一定要尽可能减少页面的重排重绘,例如页面图片大小变化、元素位置变化这些情况都会导致重排与重绘。
(3)使用CSS3动画,开启GPU加速
使用CSS3动画可以设置transform: translateZ(0)来开启移动设备浏览器的GPU图形处理加速。GPU加速是什么。
(4)合理使用canvas和requestAnimationFrame
选择canvas或者requestAnimationFrame等更高效的动画实现方式,避免使用settimeout、setInterval等方式直接处理连续动画.
(5)SVG代替图片
部分情况下可以考虑使用SVG代替图片实现动画,因为SVG格式内容更小,而且SVG的DOM结构方便调整。
(6)不滥用float
在DOM渲染树生成后的布局渲染阶段,使用float的元素布局计算比较耗性能,所以尽量减少float的使用,推荐使用固定布局或者flex布局的方式来实现页面的元素布局。
(7)不滥用web字体或过多的font-size声明
过多的font-size声明会增加字体的计算大小。
架构协议
(1)尝试使用SPDY和HTTP2
在条件允许的情况下可以考虑使用SPDY协议来进行文件资源传输,利用连接复用加快传输过程,缩短资源加载时间。
(2)使用后端数据渲染
SSR( Server Side Rendering,服务端渲染)的方式可以加速页面内容的渲染展示,避免空白页面的出现,同时可以解决页面SEO的问题。条件允许的话,SSR是一个很好的实践思路。百度SSP单页式应用性能优化实践,React 同构实践与思考。
(3)使用Native View代替DOM的性能劣势
可以尝试使用Native View的MNV* 开发模式来避免HTML DOM性能慢的问题,目前使用MNV* 的开发模式已经可以将页面内容渲染体验做到接近客户端Native应用的体验了。
3.PC端性能优化
(参考浅谈前端性能优化(PC版))
网络加载
(1)减少HTTP请求次数
根据需要合并静态资源图片、JavaScript代码和CSS文件,减少页面请求次数,这样可以缩短页面首次访问的等待时间,另外也要尽量的避免重复资源,防止增加多余的请求。
(2)减少HTTP请求大小
比如减少没必要的图片、JS、CSS以及HTML等,对文件进行压缩优化,开启GZIP压缩传输内容,缩短网络传输等待延迟。
(3)将CSS和JS放到外部文件中,避免使用style和script标签引入
在HTML文件中引入外部的资源可以有效利用浏览器的静态资源缓存。
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js">script>
(4)避免页面中空的href和src
当link标签的href属性为空,或者script、img、iframe标签的src属性为空的时候,浏览器在渲染的过程中还是会把href和src的空内容进行加载,直到加载失败。这样就阻塞了页面中其他资源的下载进程,并且最后加载的内容是无效的,因此要尽量避免。
<img src="" alt="占位图"/>
(5)为HTML指定Cache-Control或者Expires
为HTML指定Cache-Control或者Expires可以将HTML内容缓存起来,避免频繁向服务器发送请求。在页面Cache-Control或Expires头部又消失,浏览器会直接从缓存读取内容,不向服务器发送请求。
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta http-equiv="expires" content="Wed, 20 Jun 2017 22:33:00 GMT">
(6)合理设置Etag和Last-Modified
对于未修改的文件,静态资源服务器会向浏览器端返回304,让浏览器从缓存中读取文件,减少下载的带宽消耗并能减少服务器的负载。
<meta http-equiv="last-modified" content="Mon, 03 Jan 2017 17:45:57 GMT">
(7)减少页面重定向
一次重定向大概600毫秒的时间开销,为了保证用户能尽快看到页面内容,尽量避免页面的重定向。
(8)静态资源不同域名存放
浏览器在同一时刻向同一个域名请求文件的并行下载数是有限的,因此可以利用多个域名的主机来存放不同的静态资源,增大页面加载时资源的并行下载数。
(9)使用静态资源CDN来存储文件
(10)使用CDN Combo下载传输内容
CDN的combo技术能把多个资源文件合并引用,减少请求次数。这样可以减少浏览器HTTP请求数,加快资源下载速度。比如淘宝的写法:
<link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/??sm.min.css,sm-extend.min.css">
<script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/??sm.min.js,sm-extend.min.js' charset='utf-8'>script>
(11)使用可缓存的AJAX
对于内容相同的请求,有时候没必要每次都从服务器拉取,合理的使用ajax缓存能加快ajax响应速度并减少服务器的压力。
$.ajax({
url : url,
dataType : "json",
cache: true,
success: function(data){ // to do something... }
});
(12)使用get请求
POST请求会首先发送文件头,然后发送HTTP正文的数据。而使用GET只发送头部,所以在拉取数据时使用GET请求效率更高。
(13)减少Cookie的大小并进行Cookie隔离
HTTP请求默认是会带上浏览器端的Cookie一起发送给服务器端的,所以在非必要的情况下要尽量减少Cookie。对于静态的资源,尽量使用不同的域名存放,因为Cookie默认也是不能跨域的,这就做到了不同域名下静态资源请求的Cookie隔离。
(14)减少favicon.ico 并缓存
一般一个web应用的favicon.ico是很少改变的,有利于favicon.ico的重复加载。
(15)异步的加载JavaScript资源
异步的JavaScript资源不会阻塞文档解析,所以浏览器会优先渲染页面,延迟加载脚本执行。
<script src="main.js" defer>script>
<script src="main.js" async>script>
(16)消除阻塞页面的CSS和JS
对于页面中加载时间过长的CSS或JS文件,需要进行合理的拆分或者延后加载,保证关键的资源能快速加载完成。
(17)避免使用CSS import 引用加载CSS
(18)使用prefetch来完成网站预加载
让浏览器预先加载用户访问当前页后极有可能访问的其他资源(页面,图片,视频等),从而让用户有更好的体验。
(19)按需加载
页面渲染类
(1)把CSS资源引用放到HTML文件顶部
这样浏览器可以优先下载CSS并尽快完成页面渲染。
(2)JavaScript文件引用放到HTML文件底部
可以防止JavaScript的加载和解析执行对页面渲染造成阻塞。由于JavaScript资源默认是解析阻塞的,除非被标记为异步或者通过其他的方式异步加载,否则会阻塞HTML DOM解析和CSS渲染过程。
(3)不要在HTML中直接缩放图片
在HTML中直接缩放图片会导致页面内容的重排重绘,此时可能会使页面中的其他操作产生卡顿,因此要尽量减少在页面中直接进行图片缩放。
(4)减少DOM元素数量和深度
HTML中标签元素越多、层级越深,浏览器解析DOM并绘制到浏览器中所花的时间就越长。
(5)尽量避免使用table、iframe等慢元素
table内容的渲染是将table的DOM渲染树全部生成完并一次性绘制到页面上,所以在长表格渲染时很耗性能,应该尽量避免使用,可以考虑用ul代替。尽量使用异步的方式动态的加载iframe,因为iframe内资源的下载进程会阻塞父页面静态资源的下载以及HTML DOM的解析。
(6)避免运行耗时的JavaScript
长时间运行的JavaScript会阻塞浏览器构建DOM树、DOM渲染树、渲染页面。所以任何与页面初次渲染无关的逻辑功能都应该延迟加载执行,这和JavaScript资源的异步加载思路一致。
(7)避免使用CSS表达式和CSS滤镜
CSS表达式和滤镜的解析渲染速度是很慢的,再有其他解决方案的情况下应该尽量避免使用。
// 不推荐
.opacity{
filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=10, MakeShadow=false)
}
4.SEO优化
(参考前端SEO优化)
SEO简介:
全称Search Engine Optimization,搜索引擎优化。
存在的意义:为了提升网页在搜索引擎自然搜索结果中的收录数量以及排序位置而做的优化行为。
分类:白帽SEO和黑帽SEO。白帽SEO,起到了改良和规范网站设计的作用,使网站对搜索引擎和用户更加友好,并且网站也能从搜索引擎中获取合理的流量,这是搜索引擎鼓励和支持的。黑帽SEO,利用和放大搜索引擎政策缺陷来获取更多用户的访问量,这类行为大多是欺骗搜索引擎,一般搜索引擎公司是不支持与鼓励的。
白帽SEO能做什么呢?
(1)对网站的标题、关键字、描述精心设置,反映网站的定位,让搜索引擎明白网站是做什么的;
(2)网站内容优化:内容与关键字的对应,增加关键字的密度;
(3)在网站上合理设置Robot.txt文件;
(4)生成针对搜索引擎友好的网站地图;
(5)增加外部链接,到各个网站上宣传;
SEO优化方案:
网站结构布局优化:
(1)控制首页链接数量:链接太少,搜索引擎往下爬到页内,影响网站收录数量;链接太多,影响用户体验。
(2)扁平化的目录层次:建立的网站结构层次越少,越容易被抓取,保持三层目录结构也是用户体验的需要。
(3)导航优化:导航尽量采用文字,也可以搭配图片导航,但图片需进行优化,如标签必须加’alt’和’title’属性;尽量加上面包屑导航,让用户更好了解当前所在位置,理解网站布局,让搜索引擎了解网站结构,同时增加了大量的内部链接,方便数据抓取。
(img图片标签alt和title属性的区别:alt是给搜索引擎识别,在图像无法显示时的替代文本;title是关于元素的注释信息,主要是给用户解读,当鼠标放到文字或是图片上时有title文字显示。)
(4)控制页面大小,减少http请求,提高网站加载速度。
(5)合理的网站布局
页面头部:logo、主导航、用户信息
页面主题:左边正文(包括面包屑导航及正文),右边热门文章和相关文章
页面底部:版权信息、友情链接
网站代码优化
(1)
标题:只强调重点即可,尽量把重要的关键词放在前面,关键词不要重复出现,尽量做到每个页面的
标题中不要设置相同的内容。
(2)标签:关键词,列举出几个页面的重要关键字即可,切记过分堆砌。
(3)标签:网页描述,需要高度概括网页内容,切记不能太长,过分堆砌关键词,每个页面也要有所不同。
(4)中的标签:尽量让代码语义化,在适当的位置使用适当的标签,用正确的标签做正确的事。让阅读源码者和“蜘蛛”都一目了然。比如:h1-h6 是用于标题类的,nav标签是用来设置页面主导航的等。
(5)a标签:页内链接,要加“title”属性加以说明,让访客和“蜘蛛”知道。而外部链接,链接到其他网站的,则需要加上rel="nofollow"属性,告诉“蜘蛛”不要爬,因为一旦“蜘蛛”爬了外部链接之后,就不会再回来了。
(6)正文标题要用h1标签:搜索引擎认为它最重要,若不喜欢它的默认样式可以通过CSS设置。尽量做到正文标题用h1标签,副标题用h2标签,而其它地方不应该随便乱用 h 标题标签。
(7)br标签:只用于文本内容的换行
(8)表格应该使用caption表格标题标签
(9)img应使用 “alt” 属性加以说明
(10)strong、em标签:需要强调时使用。strong标签在搜索引擎中能够得到高度的重视,它能突出关键词,表现重要的内容,em标签强调效果仅次于strong标签。b、i标签: 只是用于显示效果时使用,在SEO中不会起任何效果。
(11)文本缩进不要使用特殊符号’ ’;应当使用CSS进行设置。版权符号不要使用特殊符号 ‘©’; 可以直接使用输入法,拼“banquan”,选择序号5就能打出版权符号©。
(12)巧妙利用CSS布局,将重要内容的HTML代码放在最前面:最前面的内容被认为是最重要的,优先让“蜘蛛”读取,进行内容关键词抓取。
(13)重要内容不要用JS输出:因为“蜘蛛”不认识。
(14)尽量少使用iframe框架:因为“蜘蛛”一般不会读取其中的内容。
(15)谨慎使用 ‘display:none’:对于不想显示的文字内容,应当设置z-index或设置到浏览器显示器之外,因为搜索引擎会过滤掉display:none其中的内容。
(16)js代码如果是操作DOM操作,应尽量放在body结束标签之前,html代码之后。
(17)增加网站的404页面:一是有利于提高用户体验,最主要的是防止蜘蛛爬虫丢失。
(18)添加canonical标签:当我们的网页可以通过多个URL来访问时,我们可以通过添加canonical标签告诉搜索引擎这多个URL中的首选网址。通常搜索引擎会将指定的页面视为最有价值最规范的页面。
<link rel=”canonical” href=”http://www.xxxxxx.com/” />
5.列举IE 与其他浏览器不一样的特性
(1)IE支持currentStyle,Firefox使用getComputedStyle;
(2)IE 使用innerText,Firefox使用textContent;
(3)滤镜方面:IE:filter:alpha(opacity= num);Firefox:-moz-opacity:num;
(4)事件方面:IE:attachEvent:火狐是addEventListener;
(5)鼠标位置:IE是event.clientX;火狐是event.pageX;
(6)IE使用event.srcElement;Firefox使用event.target;
(7)IE中消除list的原点仅需margin:0即可达到最终效果;Firefox需要设置margin:0;padding:0以及list-style:none;
(8)CSS圆角:ie7以下不支持圆角。
6.99%的网站都需要被重构是那本书上写的?
《网站重构:应用Web标准进行设计(第2版)》
7.WEB应用从服务器主动推送Data到客户端有哪些方式?
(1)Javascript数据推送;
(2)Commet:基于HTTP长连接的服务器推送技术;
(3)基于WebSocket的推送方案;
(4)SSE(Server-Send Event):服务器推送数据新方式。
8.对Node的优点和缺点提出了自己的看法?
NodeJS的特点:
(1)Javascript运行环境;
(2)依赖于Chrome V8引擎进行代码解释;
(3)事件驱动;
(4)非阻塞I/O;
(5)轻量、可伸缩,适于实时数据交互应用;
(6)单进程,单线程。
优点:
(1)高并发(最重要的优点);
因为Node是基于事件驱动和无阻塞的,所以非常适合处理并发请求,因此构建在Node上的代理服务器相比其他技术实现(如Ruby)的服务器表现要好得多。
(2)适合I/O密集型应用;
(3)客户端和服务器端同一种语言编写。
缺点:
(1)不适合CPU密集型应用;
CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起;
解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起;
(2)只支持单核CPU,不能充分利用CPU;
(3)可靠性低,一旦代码某个环节崩溃,整个系统都崩溃;
原因:单进程,单线程
解决方案:1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;
2)开多个进程监听同一个端口,使用cluster模块;
(4)开源组件库质量参差不齐,更新快,向下不兼容;
(5)Debug不方便,错误没有stack trace。
适合NodeJS的场景:
(1)RESTful API
这是NodeJS最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。
它本质上只是从某个数据库中查找一些值并将它们组成一个响应。
由于响应是少量文本,入站请求也是少量的文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的API需求。
(2)统一Web应用的UI层
目前MVC的架构,在某种意义上来说,Web开发有两个UI层,一个是在浏览器里面我们最终看到的,另一个在server端,负责生成和拼接页面。
不讨论这种架构是好是坏,但是有另外一种实践,面向服务的架构,更好的做前后端的依赖分离。如果所有的关键业务逻辑都封装成REST调用,就意味着在上层只需要考虑如何用这些REST接口构建具体的应用。
(3)大量Ajax请求的应用
例如个性化应用,每个用户看到的页面都不一样,缓存失效,需要在页面加载的时候发起Ajax请求, NodeJS能响应大量的并发请求。
总而言之,NodeJS适合运用在高并发、I/O密集、少量业务逻辑的场景。
9.一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
(1)浏览器的地址栏输入URL并按下回车;
(2)浏览器查找当前URL是否存在缓存,并比较缓存是否过期;
(3)DNS解析URL对应的IP;
(4)根据IP建立TCP连接(三次握手);
(5)HTTP发起请求;
(6)服务器处理请求,浏览器接收HTTP响应;
(7)渲染页面,构建DOM树;
(8)关闭TCP连接(四次挥手)。
URL:
我们常见的URL是这样的:http://www.baidu.com,这个域名由三部分组成:协议名、域名、端口号,这里端口是默认所以隐藏。除此之外URL还会包含一些路径、查询和其他片段,例如:http://www.tuicool.com/search?kw=%E4%。
最常见的的协议是HTTP协议,除此之外还有加密的HTTPS协议、FTP协议、FILe协议等等。
URL的中间部分为域名或者是IP,之后就是端口号了。通常端口号不常见是因为大部分的都是使用默认端口,如HTTP默认端口80,HTTPS默认端口443。
缓存
根据是否需要重新向服务器发起请求来分类,将其分为强制缓存,对比缓存。
强制缓存判断HTTP首部字段:cache-control,Expires。
Expires是一个绝对时间,即服务器时间。浏览器检查当前时间,如果还没到失效时间就直接使用缓存文件。但是该方法存在一个问题:服务器时间与客户端时间可能不一致。因此该字段已经很少使用。
cache-control中的max-age保存一个相对时间。例如Cache-Control: max-age = 484200,表示浏览器收到文件后,缓存在484200s内均有效。如果同时存在cache-control和Expires,浏览器总是优先使用cache-control。
对比缓存通过HTTP的last-modified,Etag字段进行判断。
last-modified是第一次请求资源时,服务器返回的字段,表示最后一次更新的时间。下一次浏览器请求资源时就发送if-modified-since字段。服务器用本地Last-modified时间与if-modified-since时间比较,如果不一致则认为缓存已过期并返回新资源给浏览器;如果时间一致则发送304状态码,让浏览器继续使用缓存。
Etag:资源的实体标识(哈希字符串),当资源内容更新时,Etag会改变。服务器会判断Etag是否发生变化,如果变化则返回新资源,否则返回304。
DNS域名解析
在地址栏输入的域名并不是最后资源所在的真实位置,域名只是与IP地址的一个映射。网络服务器的IP地址那么多,我们不可能去记一串串的数字,因此域名就产生了,域名解析的过程实际是将域名还原为IP地址的过程。
(1)首先浏览器先检查本地hosts文件是否有这个网址映射关系,如果有就调用这个IP地址映射,完成域名解析;
(2)如果没找到则会查找本地DNS解析器缓存,如果查找到则返回;
(3)如果还是没有找到则会查找本地DNS服务器,如果查找到则返回;
(4)最后迭代查询,按根域服务器 ->顶级域,.cn->第二层域,hb.cn ->子域,www.hb.cn的顺序找到IP地址。
TCP连接
在通过第一步的DNS域名解析后,获取到了服务器的IP地址,在获取到IP地址后,便会开始建立一次连接,这是由TCP协议完成的,主要通过三次握手进行连接。
(1)第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;
(2)第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
(3)第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
浏览器向服务器发送HTTP请求
完整的HTTP请求包含请求起始行、请求头部、请求主体三部分。
浏览器接收响应
服务器在收到浏览器发送的HTTP请求之后,会将收到的HTTP报文封装成HTTP的Request对象,并通过不同的Web服务器进行处理,处理完的结果以HTTP的Response对象返回,主要包括状态码、响应头、响应报文三个部分。
响应头主要由Cache-Control、 Connection、Date、Pragma等组成。
响应体为服务器返回给浏览器的信息,主要由HTML,css,js,图片文件组成。
页面渲染
如果说响应的内容是HTML文档的话,就需要浏览器进行解析渲染呈现给用户。整个过程涉及两个方面:解析和渲染。在渲染页面之前,需要构建DOM树和CSSOM树。
关闭TCP连接或继续保持连接
通过四次挥手关闭连接(FIN ACK, ACK, FIN ACK, ACK)。
第一次挥手是浏览器发完数据后,发送FIN请求断开连接;第二次挥手是服务器发送ACK表示同意,如果在这一次服务器也发送FIN请求断开连接似乎也没有不妥,但考虑到服务器可能还有数据要发送,所以服务器发送FIN应该放在第三次挥手中;这样浏览器需要返回ACK表示同意,也就是第四次挥手。
10.HTTP
HTTP请求四部分:
(1)HTTP请求的方法或动作,比如是get还是post请求;
(2)正在请求的URL(请求的地址);
(3)请求头,包含一些客户端环境信息、身份验证信息等;
(4)请求体(请求正文),可以包含客户提交的查询字符串信息、表单信息等。
请求头字段:
Accept:text/html,image/*(告诉服务器,浏览器可以接受文本,网页图片)
Accept-Charaset:ISO-8859-1 [接受字符编码:iso-8859-1]
Accept-Encoding:gzip,compress[可以接受 gzip,compress压缩后数据]
Accept-Language:zh-cn[浏览器支持的语言]
Host:localhost:8080[浏览器要找的主机]
If-Modified-Since:Tue, 09 May 2017 01:34:02 GMT[告诉服务器我这缓存中有这个文件,该文件的时间是…]
User-Agent:Nozilla/4.0(Com…)[告诉服务器我的浏览器内核,客户端环境信]
Cookie:[身份验证信息]
Connection:close/Keep-Alive [保持链接,发完数据后,我不关闭链接]
HTTP响应三部分:
(1)一个数字和文字组成的状态码,用来显示请求是成功还是失败;
(2)响应头,响应头也和请求头一样包含许多有用的信息,例如服务器类型、日期时间、内容类型和长度等;
(3)响应体(响应正文)。
响应头字段:
Cache-Control:[告诉浏览器如何缓存页面(因为浏览器的兼容性最好设置两个)]
Connection:close/Keep-Alive [保持链接,发完数据后,我不关闭链接]
Content-Type:text/html;charset=gb2312[内容格式和编码]
Last-Modified:Tue,11 Juj,2017 18 18:29:20[告诉浏览器该资源上次更新时间是多少]
ETag:”540-54f0d59b8b680”
Expires:Fri, 26 May 2017 13:28:33 GMT [失效日期]
server:apache tomcat nginx [哪种服务器]
11.常见HTTP状态码
(1)1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态码;
100 Continue 一般在发送post请求时已发送了http header之后服务端将返回此信息,表示确认,之后发送具体参数信息。
(2)2xx(成功)表示成功处理了请求的状态码;
200 OK 正常返回信息,服务器已成功处理了请求;
201 Created 请求成功并且服务器创建了新的资源;
202 Accepted 服务器已接受请求,但尚未处理 。
(3)3xx(重定向)要完成请求,需要进一步操作;
301(永久移动):请求的网页已永久移动到新位置;
302(临时移动):服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求;
303 See Other 临时性重定向,且总是使用 GET 请求新的 URI;
304(未修改):自从上次请求后,请求的网页未修改过。
(4)4xx(请求错误)这些状态码表示请求可能出错,妨碍了服务器的处理。
400(错误请求):服务器不理解请求的语法;
403 Forbidden 禁止访问;
404(未找到):服务器找不到请求的网页。
(5)5xx(服务器错误)这些状态码表示服务器在处理请求时发生内部错误。
500(服务器内部错误):服务器遇到错误,无法完成请求。
503(服务不可用):服务器目前无法使用(由于超载或停机维护)。
12.简单理解HTTP HTTPS 以及TCP 和UDP 的区别
HTTP和HTTPS的基本概念
HTTP:
HTTP是超文本传输协议,是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。在Internet上的Web服务器上存放的都是超文本信息, 客户机需要通过HTTP协议传输所要访问的超文本信息。HTTP包含命令和传输信息,不仅可用于Web访问,也可以用于其他因特网/内联网应用系统之间的通信,从而实现各类应用资源超媒体访问的集成。
HTTPS:
是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
HTTP与HTTPS的区别
HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
HTTPS和HTTP的区别主要如下:
(1)https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用;
(2)http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议;
(3)http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443;
(4)http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
HTTPS的工作原理
HTTPS能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。
客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤:
(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接;
(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端;
(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
(5)Web服务器利用自己的私钥解密出会话密钥。
(6)Web服务器利用会话密钥加密与客户端之间的通信。
HTTPS的优点
尽管HTTPS并非绝对安全,掌握根证书的机构、掌握加密算法的组织同样可以进行中间人形式的攻击,但HTTPS仍是现行架构下最安全的解决方案,主要有以下几个好处:
(1)使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
(2)HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中被窃取、改变,确保数据的完整性;
(3)HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本;
(4)谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。
HTTPS的缺点
(1)HTTPS协议握手阶段比较费时,会使页面的加载时间延长近50%,增加10%到20%的耗电;
(2)HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
(3)SSL证书需要钱,功能越强大的证书费用越高,个人网站、小网站没有必要一般不会用。
(4)SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
(5)HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可行。
HTTP切换到HTTPS
需要将页面中所有的链接,例如js,css,图片等等链接都由http改为https。例如:http://www.baidu.com改为https://www.baidu.com。这里虽然将http切换为了https,还是建议保留http。在切换的时候可以做http和https的兼容,具体实现方式是,去掉页面链接中的http头部,这样可以自动匹配http头和https头。例如:将http://www.baidu.com改为//www.baidu.com。然后当用户从http的入口进入访问页面时,页面就是http,如果用户是从https的入口进入访问页面,页面即使https的。
TCP/UDP:
面向连接的TCP
“面向连接”就是在正式通信前必须要与对方建立起连接。比如你给别人打电话,必须等线路接通了、对方拿起话筒才能相互通话。
TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。
TCP协议能为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错地发往网络上的其他计算机,对可靠性要求高的数据通信系统往往使用TCP协议传输数据。
面向非连接的UDP协议
“面向非连接”就是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。这与手机短信非常相似:你在发短信的时候,只需要输入对方手机号就OK了。
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!UDP 适用于一次只传送少量数据、对可靠性要求不高的应用环境。
13.http1.0,http1.1,http2.0区别
HTTP1.0和HTTP1.1的一些区别
(1)缓存处理
在HTTP1.0中主要使用header里的If-Modified-Since,Expires来作为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
(2)带宽优化及网络连接的使用
HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
(3)错误通知的管理
在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
(4)Host头处理
在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
(5)长连接
HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
(6)HTTP1.1增加了OPTIONS, PUT, DELETE, TRACE, CONNECT这些Request方法.
http2.0与http1.x
(1)新的二进制格式(Binary Format)
HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
(2)多路复用(MultiPlexing)
即连接共享,即每一个request都是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里。
(3)header压缩
HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
(4)服务端推送(server push)
同SPDY一样,HTTP2.0也具有server push功能。例如我的网页有一个sytle.css的请求,在客户端收到sytle.css数据的同时,服务端会将sytle.js的文件推送给客户端,当客户端再次尝试获取sytle.js时就可以直接从缓存中获取到,不用再发请求了。
14.什么是Http协议无状态协议?怎么解决Http协议无状态?
无状态协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,也就是说,当客户端一次HTTP请求完成以后,客户端再发送一次HTTP请求,HTTP并不知道当前客户端是一个“老用户”。
可以使用Cookie来解决无状态的问题,Cookie就相当于一个通行证,第一次访问的时候给客户端发送一个Cookie,当客户端再次来的时候,拿着Cookie(通行证),那么服务器就知道这个是“老用户”。
15.URI和URL的区别
URI
uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个用URI来定位的。
URI一般由三部分组成:
(1)访问资源的命名机制
(2)存放资源的主机名
(3)资源自身的名称,由路径表示,着重强调于资源。
URL
uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。
URL一般由三部组成:
(1)协议(或称为服务方式)
(2)存有该资源的主机IP地址(有时也包括端口号)
(3)主机资源的具体地址。如目录和文件名等
URN
uniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com。
URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。
16.常用的HTTP方法有哪些?
GET: 请求指定的页面信息,并返回页面主体
HEAD:类似于GET请求,只不过返回的响应中没有具体的内容,用于获取报头
POST:向指定资源提交数据并进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立或已有资源的修改。
PUT:从客户端向服务器传送的数据取代指定的文档的内容
DELETE:请求服务器删除指定的页面
CONNECT:HTTP1.1协议中预留给能够将连接改为管道方式的代理服务器
OPTIONS:允许客户端查看服务器的性能
TRACE:回显服务器收到的请求,主要用于测试或诊断
17.GET与POST方法的区别
post请求的过程:
(1)浏览器请求tcp连接(第一次握手)
(2)服务器答应进行tcp连接(第二次握手)
(3)浏览器确认,并发送post请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
(4)服务器返回100 Continue响应
(5)浏览器发送数据
(6)服务器返回200 OK响应
get请求的过程:
(1)浏览器请求tcp连接(第一次握手)
(2)服务器答应进行tcp连接(第二次握手)
(3)浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
(4)服务器返回200 OK响应
区别:
(1)效率
GET从服务器获取数据(也可以上传数据,参数就是),效率较高
POST可以向服务器发送数据和下载数据,效率不如GET
原因:
1)post请求包含更多的请求头
因为post需要在请求的body部分包含数据,所以会多了几个数据描述部分的首部字段(如:content-type),这其实是微乎其微的。
2)post在真正接收数据之前会先将请求头发送给服务器进行确认,然后才真正发送数据。
(2)缓存
GET 请求能够被缓存,默认的请求方式也是有缓存的,POST请求默认不会缓存。
原因:
缓存是针对URL来进行缓存的,GET请求其参数是直接加在URL上的,一种参数组合就有一种URL的缓存,可以根据参数来进行一一对应,重复请求是幂等的(不论请求多少次,结果都一样);
而POST请求的URL没有参数,每次请求的URL都相同,数据体(HTTPBody)可能不同,无法一一对应,所以缓存没有意义。
(3)安全性
GET的所有参数全部包装在URL中,明文显示,且服务器的访问日志会记录,非常不安全;
POST的URL中只有资源路径,不包含参数,参数封装在二进制的数据体中,服务器也不会记录参数,相对安全,所有涉及用户隐私的数据都要用POST传输。
POST的安全是相对的,对于普通用户来说他们看不到明文,数据封装对他们来说就是屏障。但是对于专业人士,它们会抓包会分析,没有加密的数据包对他们来说也是小case。所以POST仅仅是相对安全,唯有对数据进行加密才会更安全。当然加密也有被破解的可能性,理论上所有的加密方式都可以破解,只是时间长短的问题。而加密算法要做的就是使得破解需要的时间尽量长,越长越安全。由于我们也需要解密,加密算法太过复杂也并非好事,这就要结合使用情况进行折中或者足够实际使用即可。
(4)数据量
HTTP协议中均没有对GET和POST请求的数据大小进行限制,但是实际应用中它们通常受限于软硬件平台的设计和性能。
GET:不同的浏览器和服务器不同,一般限制在2~8K之间,更加常见的是1k以内;
POST方法提交的数据比较大,大小靠服务器的设定值限制,PHP默认是2M。
18.表单提交中get和post方式的区别归纳如下几点:
(1)get是从服务器上获取数据,post是向服务器传送数据。
(2)对于表单的提交方式,在服务器端只能用Request.QueryString来获取Get方式提交来的数据,用Post方式提交的数据只能用Request.Form来获取。
(3)一般来说,尽量避免使用Get方式提交表单,因为有可能会导致安全问题。比如说在登陆表单中用Get方式,用户输入的用户名和密码将在地址栏中暴露无遗。但是在分页程序中,用Get方式就比用Post好。
在响应中唯一真正的区别在于第一行中用状态信息代替了请求信息。状态行(status line)通过提供一个状态码来说明所请求的资源情况。
19.你觉得前端工程的价值体现在哪?
(1)为简化用户使用提供技术支持(交互部分);
(2)为多个浏览器兼容性提供支持;
(3)为提高用户浏览速度(浏览器性能)提供支持;
(4)为跨平台或者其他基于webkit或其他渲染引擎的应用提供支持;
(5)为展示数据提供支持(数据接口)。
20.平时如何管理你的项目?
(1)先期团队必须确定好全局样式(globe.css),编码模式(utf-8) 等;
(2)编写习惯必须一致(例如都是采用继承式的写法,单样式都写成一行);
(3)标注样式编写人,各模块都及时标注(标注关键样式调用的地方);
(4)页面进行标注(例如 页面模块开始和结束);
(5)CSS跟HTML 分文件夹并行存放,命名都得统一(例如style.css);
(6)JS 分文件夹存放命名以该JS 功能为准英文翻译;
(7)图片采用整合的 images.png png8 格式文件使用尽量整合在一起使用方便将来的管理。