代码:https://github.com/zhaobao1830/xingnengyouhuajavascript
一、web前端本质上是一种前端GUI(图形界面系统)软件,本能够直接借鉴其余GUI系统架构设计方法。但web前端有点特别php
B/Scss
二、浏览器的一个请求从发送到返回都经历了什么?html
script
标签的话,会判断是否存在 async
或者 defer
,前者会并行进行下载并执行 JS,后者会先下载文件,而后等待 HTML 解析完成后顺序执行,若是以上都没有,就会阻塞住渲染流程直到 JS 执行完毕。遇到文件下载的会去下载文件,这里若是使用 HTTP 2.0 协议的话会极大的提升多图的下载效率。DOMContentLoaded
事件
三、请求过程当中一些潜在的性能优化点前端
dns是否能够经过缓存减小dns查询时间?vue
网络请求的过程走最近的网络环境?java
相同的静态资源是否能够缓存?node
可否减小请求http请求大小? react
减小http请求(将多个js文件合并)webpack
服务端渲染
具体来讲,DNS 解析花时间,能不能尽可能减小解析次数或者把解析前置?能——浏览器 DNS 缓存和 DNS prefetch。TCP 每次的三次握手都急死人,有没有解决方案?有——长链接、预链接、接入 SPDY 协议。若是说这两个过程的优化每每须要咱们和团队的服务端工程师协做完成,前端单方面能够作的努力有限,那么 HTTP 请求呢?——在减小请求次数和减少请求体积方面,咱们应该是专家!再者,服务器越远,一次请求就越慢,那部署时就把静态资源放在离咱们更近的 CDN 上是否是就能更快一些?
以上提到的都是网络层面的性能优化。再往下走就是浏览器端的性能优化——这部分涉及资源加载优化、服务端渲染、浏览器缓存机制的利用、DOM 树的构建、网页排版和渲染过程、回流与重绘的考量、DOM 操做的合理规避等等——这正是前端工程师能够真正一展拳脚的地方。学习这些知识,不只能够帮助咱们从根本上提高页面性能,更可以大大加深我的对浏览器底层原理、运行机制的理解,一箭双雕!
四、Gzip 压缩原理
说到压缩,可不仅是构建工具的专利。咱们平常开发中,其实还有一个便宜又好用的压缩操做:开启 Gzip。
具体的作法很是简单,只须要你在你的 request headers 中加上这么一句:
accept-encoding:gzip
HTTP 压缩是一种内置到网页服务器和网页客户端中以改进传输速度和带宽利用率的方式。在使用 HTTP 压缩的状况下,HTTP 数据在从服务器发送前就已压缩:兼容的浏览器将在下载所需的格式前宣告支持何种方法给服务器;不支持压缩方法的浏览器将下载未经压缩的数据。最多见的压缩方案包括 Gzip 和 Deflate。... https://juejin.im 掘金 — 一个帮助开发者成长的社区
HTTP 压缩就是以缩小体积为目的,对 HTTP 内容进行从新编码的过程
Gzip 的内核就是 Deflate,目前咱们压缩文件用得最多的就是 Gzip。能够说,Gzip 就是 HTTP 压缩的经典例题。
若是你的项目不是极端迷你的超小型文件,我都建议你试试 Gzip。
有的同窗或许存在这样的疑问:压缩 Gzip,服务端要花时间;解压 Gzip,浏览器要花时间。中间节省出来的传输时间,真的那么可观吗?
答案是确定的。若是你手上的项目是 1k、2k 的小文件,那确实有点高射炮打蚊子的意思,不值当。但更多的时候,咱们处理的都是具有必定规模的项目文件。实践证实,这种状况下压缩和解压带来的时间开销相对于传输过程当中节省下的时间开销来讲,能够说是微不足道的。
首先要认可 Gzip 是高效的,压缩后一般能帮咱们减小响应 70% 左右的大小。
但它并不是万能。Gzip 并不保证针对每个文件的压缩都会使其变小。
Gzip 压缩背后的原理,是在一个文本文件中找出一些重复出现的字符串、临时替换它们,从而使整个文件变小。根据这个原理,文件中代码的重复率越高,那么压缩的效率就越高,使用 Gzip 的收益也就越大。反之亦然。
通常来讲,Gzip 压缩是服务器的活儿:服务器了解到咱们这边有一个 Gzip 压缩的需求,它会启动本身的 CPU 去为咱们完成这个任务。而压缩文件这个过程自己是须要耗费时间的,你们能够理解为咱们以服务器压缩的时间开销和 CPU 开销(以及浏览器解析压缩文件的开销)为代价,省下了一些传输过程当中的时间开销。
既然存在着这样的交换,那么就要求咱们学会权衡。服务器的 CPU 性能不是无限的,若是存在大量的压缩需求,服务器也扛不住的。服务器一旦所以慢下来了,用户仍是要等。Webpack 中 Gzip 压缩操做的存在,事实上就是为了在构建过程当中去作一部分服务器的工做,为服务器分压。
所以,这两个地方的 Gzip 压缩,谁也不能替代谁。它们必须和平共处,好好合做。做为开发者,咱们也应该结合业务压力的实际强度状况,去作好这其中的权衡。
四、网络请求的时候,会出现网络选择和缓存的问题,咱们通常用cdn,可是cdn也有一个问题,cdn是请求静态资源用的,请求中携带的cookie是没有用的,因此咱们但愿在请求的过程当中把cookie从http.request.header中去掉,可是不少时候cdn的域名会弄得和自己网站的域名相同,就会将咱们主站的cookie经过网络去携带到咱们的cdn的服务端,这个是对网络无谓的损耗,因此咱们必定要注意,cdn的域名不要和主站的域名同样,这样就能够防止访问cdn的时候,还携带主站cookie这个问题
五、经过浏览器的缓存策略,咱们能够对相同的资源和相同的接口从浏览器的缓存中读取数据
六、如今流行的一些框架,好比:vue、react都是在浏览器端渲染,不是直接显示html,是走框架中的代码渲染,这个渲染过程对于首屏就有很大的损耗,不利于前端的性能的,这种场景下,咱们就有一个服务端渲染的方案,在服务端进行整个html的渲染,从而将整个html指出到浏览器端。因此咱们能够作一些服务器端渲染优化的方案
七、
8
九、
js压缩的意义:减小网路请求的大小;浏览器并发请求的数量是有限的,压缩之后,减小请求数量
十、没有合并文件会出现的问题
十一、
文件合并之后,若是页面显示,须要JS文件支持,那就要等这个合并之后的JS请求完成,首屏渲染会须要很长时间。这种状况容易出如今使用框架的项目中,好比vue、react,
项目要想正常运行,就须要加载完全部文件,解决办法是使用服务器端渲染
缓存失效问题,多个js文件合并,只要有一个js文件被修改,合并文件就会被修改,以前的缓存就失效了
真实环境中,公共库不容易修改,业务代码频繁修改,因此把公共库单独打包成一个文件,业务代码单独打包成一个文件,这样业务代码修改的时候,也不会影响公共库代码的缓存
不一样页面的合并,就是单页应用中,每一个页面的展现,都是请求当前页面的JS,因此咱们把每一个页面的js单独打包,在加载这个页面的时候,才加载对应的js。如今的技术是能够实现的,异步加载组件
十二、
雪碧图,PC端用的多
缺点:在整个雪碧图加载完以前,里面的image都不能使用(能够拆分雪碧图)
若是页面中引入的图片比较小,那就把图片内容内嵌到html中,用base64的格式文件信息inline到html中,由于这是性能的消耗主要就是在请求图片中消耗的,若是有10个图,不可能去请求10次,最好的办法是把图片内容inline到html中,一块儿请求,这样能够减小请求数量
在作一些相对简单的页面的时候,用矢量图,用的是svg标签绘制一个矢量图,不须要通过http请求加载资源,同时也在整个dom树简析的时候就将这个svg进行渲染
十一、
并发加载:html在加载页面的时候,会引入css和js,浏览器在同一个域名下的加载数量是有限的,因此实际状况下,咱们会引入3到4个cdn,提升浏览器的并发请求上限
依赖关系:css要放在header中,否则会出如今渲染过程当中,页面忽然闪一下
引入方式:Js:第一种:直接用script引入,会出现阻塞;第二种:动态引入,加载到这个页面的时候才引入,这个主要是单页应用中
词法分析:浏览器对html简析的方式,从上到下,顺序执行
并发加载:html引入的资源是并发去请求的
并发上限:浏览器在同一个域名下并发请求是有上限的,咱们应该控制某个域名下资源请求的数量,从而避免并发上限
十二、
css在head中经过link引入,会阻塞页面的渲染
css不阻塞外部脚本的加载,可是会阻塞js的执行,好比js里须要动态改变css的样式
1三、
直接引入的js阻塞页面的渲染,例如js会调用document.write这种方式,来改变dom结构,这时渲染会暂停
defer不会阻塞页面渲染,是在dom树加载完成后再加载这个js,并且这些js的加载也是按顺序加载的
async不会阻塞页面渲染,不是按顺序加载js的,哪一个Js先返回,就加载谁。不会关心依赖关系,也不要有依赖关系,有依赖关系的脚本不要经过async引入
defer能保证dom树必定已经加载完整,只用script或者async不必定能保证
1四、link和@import的区别
低版本浏览器中:
link支持并发,@import不支持并发,一个@import文件加载完后,才会加载另外一个@import文件
整个页面加载完成后,才会执行@import中的代码
上面的俩条在高版本浏览器中已经没有了,@import也支持并发
@import的一个优势是:适合模块化开发,能够在css文件中引入另外一个css文件(注意:这种状况下,只有前一个css文件执行完,才会执行引入的这个css文件,因此要避免多层引入)
1五、懒加载
图片进入可视区域以后才会请求图片资源,以前图片的src为一个1kb的图片路径,真实的url值保持在data-url中,经过监听scroll事件,当触发的时候,将img标签上的data-url属性的值放到src中,这时src的变化就会触发相关资源的请求
懒加载多用于电商网站中
使用的缘由是由于:一个电商网站中有多个图片,有时候看浏览网站的时候,不会都看,若是把没有进入可视区域的图片也加载,会形成资源的浪费。还有一个缘由是:在网页中,img通常都在js上方,src请求的资源的时候,会占据大量的并发,进而影响Js的加载,影响网站的正常使用
在有依赖关系的场景可使用预加载,好比这个页面须要这个图片,只有这个图片加载完之后,页面才会显示
使用场景:抽奖
1六、css性能会让javascript变慢?
加载css的时候,会阻塞渲染;加载js的时候,也会阻塞渲染
在浏览器中,js解析和ul渲染是在单独的线程中,一个线程=》javascript解析,一个线程=》ui渲染,这俩个线程是互斥的,浏览器是单线程运行机制,css会影响页面的样式的展现,若是渲染的流出频繁的触发的话,就是频繁触发重绘与回流,会致使UI频繁渲染,阻塞javascript的线程,最终致使JS变慢
咱们应该优化css写法, 从而让浏览器UI渲染的次数和难度下降,从而来加快渲染的速度,让整个性能有所提高
1七、避免重绘和回流的方法
缺点:合成图层的时候,会大量消耗资源
1八、
会破坏缓存机制
二、opacity替代visibility(这个须要让dom是独立的图层):https://coding.imooc.com/lesson/130.html#mid=6521
五、能够前面定义一个变量,把获取dom属性的值赋给这个变量,而后使用这个变量进行操做
1九、浏览器存储--cookies
Cookie的生成方式:
一、服务器端生成,http response header中的set-cookie
二、经过document.cookie能够读写cookie,
获取的是cookie键值对组成的字符串:
写的时候,能够用下面这个方法:
Cookie的做用:
一、用于浏览器端和服务器端的交互
二、客户端自身数据的存储
Cookie有个很重要的属性:过时时间--expire
Cookie另外一个个很重要的属性: httponly,设置之后,js没法读取和修改cookie
Cookie存储的限制:
一、 做为浏览器存储,大小4KB左右
二、须要设置过时时间--expire
在实际的项目中,Cookie存储数据能力被localstorage所替代
cdn请求静态资源的时候,会把Cookie带上,这样会消耗大量的流量
20、
实例:
想localStorage中存储数据 localStorage.setItem('key','value')
从localStorage中获取数据 loaclStorage.getItem('name')
2一、
实例:
2二、
PWA是谷歌开发的,是一个渐进式的Web,举个例子:手机在网很差的状况下如何快速显示内容,离线状态下该如何,1G下如何,2G下如何,4G下如何
检测是不是PWA,以及网站性能
能够理解为主线程外的另外一个线程,如今的javascript是单线程的,全部的加载都在主线程中执行,js主线程能够把一些耗时比较长,不依赖页面或用户交互的特性放到这个
Service Worker中,到浏览器的后台去运行,这样能够减小主线程被阻塞的程度,同时丰富浏览器对后续特性的扩展
Service Worker俩个普遍的应用点:
1、Service Worker能够用来实现离线加载:
在没有网的状况下,发出请求,请求被Service Worker拦截,Service Worker可使用它的缓存数据进行页面加载,实际上这个时候并无把请求打到网络上,因此这时就算
没有网络,页面也能够渲染出来,后面若是有网了,就能够用请求到的资源来替换Service Worker渲染的dom
2、能够把一些须要消耗很长时间运算的,不影响页面渲染的功能放到后台进行执行,执行完之后,经过Service Worker与主页面有关的运算机制,传递给主页面,而后主页面
监听相关message的事件,就能拿到Service Worker的运算结果,从而进行页面后续逻辑的执行
Service Worker只能在https下用,本地开发中没有https,可使用localhost,不能使用ip
2三、http header端的缓存
Cache-Control
no-cache 浏览器请求会到服务器端,而后使用例如Last-Modified等方法进一步判断当前浏览器端的缓存有没有过时
no-store 没有缓存
max-age的优先级高于Expires
max-age和Expires都是强浏览器端缓存行为,意思就是这俩个属性生效的时候,不会触发向服务器端发起请求的过程,而是直接从咱们的浏览器中读相应缓存的数据。这会有一个问题:当服务端有文件更新了,客户端是不知道的,这时候就须要Last-Modified/If-Modified-Since
流程是这样的:客户端向服务器端请求,服务端返回的Response Headers里面有last-modified,高数客户端这个资源修改的最后时间是何时;客户端再请求的时候,服务端就会
查看Request Headers里面有没有if-modified-since,若是有,就进行判断,看这个时间点以后有没有修改资源,没有的话,就返回304,让客户端请求客户端的缓存资源,有的话,就返回200,而且更新last-modified。
实际工做中,last-modified会和cache-control配合使用,若是cache-control设置了缓存,就会先使用客户端的缓存资源,过时之后,才会想服务器端发出请求
is-modified是以秒为单位的,若是是在毫秒里面修改了,它是察觉不到的
2四、为了解决上面提到的last-modified的肯定,可使用下面的
原理仍是同样,服务器端的http response header里面携带ETag到客户端,客户端请求的时候,会在Request Headers里面携带if-None-Match进行判断,若是match,就使用缓存,不然向客户端发起请求
从下往上,一层一层
在第二层,ETag的优先级比if-modified高
上面这个图的原理是:
最上层:当第一次请求的时候,直接向服务端发起请求,返回的状态码是200
第二层:当下一层的缓存时间失效,就进入这一层,通过先后端协商,而后进行判断,若是后端没有修改数据,就使用前端缓存,返回的状态码是304
最下层:因为设置了缓存,因此请求的时候,使用的是浏览器缓存的资源,返回的状态码是200(from cache)
备注:ETag和last-modified都是后端tomcat或nagix设置
2五、
上面图的理解:用户从浏览器端发出请求,判断是否存在缓存,若是没有,就向服务端发起请求,服务端会请求响应,并把缓存策略告诉客户端,经过http response headers里的catche-control、Last-Modified、Etag来进行缓存协商,最终展现咱们的资源。
若是存在缓存,就会简析这个缓存文件,检查缓存文件是否已经在本地过时,经过max-age、Expires判断,若是缓存没有过时,就直接使用缓存内容,返回相关的资源展现
若是缓存时间已通过期,就会去找Etag(优先级高),在http request headers里带上if-none-match向服务器端发起请求,到了服务器端,会进行判断,这个if-none-match的hash值和我服务器端的hash值是否一致,若是相同,返回304,浏览器会去取缓存文件。若是俩个hash值不一致,就会返回200,而后返回新的数据,而且协商新的缓存机制
若是没有Etag,就走last-modified分支,以后和上面的一致
Cache-Control:
是否能够重用,若是不能够,jiushino-store
若是能够,就判断每次请求是否从新验证,若是yes,就是no-cache,不走三层策略里面的最下层,都会走中间层,进行客户端和服务器端之间的协商,会产生304的状况,经过last-modified和Etag进行相关判断
若是不须要每次请求都从新验证,就使用max-age和s-maxage。是否容许被代理服务缓存,若是no就是Private,只浏览器层面的缓存,咱们就设置为max-age;若是是Public,就是能被不少人共同使用,那它就是一个源代理服务器,或者是cdn服务器,这时候就须要设置s-maxage。最后就是设置过时时间
2七、服务端优化(前提是服务端使用了node.js,这样先后端使用的语言就同样了,可使用服务端的运算能力来进行相关的运算,从而减小前端的运算成本)
Vue渲染面临的问题是什么?
Vue的项目,在页面被渲染出来前,在客户端已经作了大量的运算,Vue的dom结构是在组件的template里面写的,这就面临一个问题,若是我整个页面要渲染出来,其实是依赖于Vue框架加载的,若是整个网站都是用Vue写的,那执行流程就是:先下载vue.js,而后执行Vue.js代码,生成相应的html页面,最后经过Vue框架把这个HTML渲染到页面里。所以,首屏显示就依赖于整个Vue加载和执行,这样会有一个性能上的损耗
使用React和Vue是有代价的,代价就是须要把框架加载完,才能把页面渲染出来
这是就有个想法:咱们能不能想jsp/php同样,在后端就渲染好,而后在前端直接展现
Vue的优势:开发体验好,组件库利于维护
怎么在vue这个层面对性能进行优化?
构建层模板编译:就是把vue代码使用webpack等工具,编译成能够run time的代码
数据无关的prerender的方式:把一些与数据无关的,全部用户都看见同样的页面,prerender掉,生成静态html,而后使用这个静态的html去访问相应的vue页面
服务端渲染(主要是为了解决首屏渲染问题):把一些常常改变的页面,在服务端渲染。在服务端执行相应的js,生成相应的html,而后在客户端直接进行渲染,把一些客户端须要执行的运算,在服务端完成