blog
blog copied to clipboard
现代前端技术解析
第一章 现代前端基础技术
前端解构的开发时期实现模式的前后经历,以及演变
- 静态黄页
- 服务器组装动态网页数据
- 后端为主的MVC模式
- 前后端分离
- 纯前端MV*为主,中间层直出
- 前端Virtual DOM,MV*前后端同构包括以next-react,nuxt-vue的后端渲染模式
我们在打开浏览器输入一个URL到页面展示这个过程中,浏览器和服务器都发生了什么?
- 在接受url时候,对url进行判断,如果是HTTP就按照HTTP方式进行处理
- 调用浏览器引擎中的对比方法,比如Webview中的loadUrl方法.
- 通过DNS解析获取该网站地址对应IP地址,查询完成后连接同浏览器的Cookie,userAgent等信息向目标网站发出的GET请求。
- 进行http协议会话,浏览器客户端向web服务器发送报文。
- 进入网站后台的web服务器处理请求,如apache,Tomcat,nodejs等服务器。
- 进入部署好的后端应用,如PHP,Java,Javascript,Python等后台程序。找到对应的请求处理逻辑,这期间可能会读取服务器缓存,或者查询数据库,
- 服务器处理请求并返回响应报文,如果服务器上面有访问过该页面,缓存上有对应资源,会与服务器最后修改记录对比,一致就返回304,否则返回200和对应内容。
- 浏览器开始下载对应HTML文档,200就下载,300就从缓存拿。
- 浏览器根据下载接收到的HTML文件解析解构建立DOM文档树。并根据HTML中的标记请求下载指定的MIME文件类型,如css,html,js等,他同时设置缓存等内容。
- 页面开始解析渲染DOM,css,根据规则解析,结合DOM文档树进行网页布局和绘制渲染,js根据DOM,api操作dom,读取浏览器缓存,执行绑定事件,整个页面展示过程完成。
通常认为浏览器一个组成部分:用户界面,网络,JavaScript引擎,渲染引擎,JavaScript执行引擎,UI后端,JavaScript解释器,和持久化数据储存。
- 用户界面:url输入框,书签等
- 浏览器引擎:可以在用户界面和渲染引擎之间传送指令,或者在客户端本地读取数据,是浏览器各部分之间通讯的核心。
- 浏览器渲染引擎:可以将html解析以及css规则解析,并将内容排版到浏览器中显示有样式的界面中,也称之为排版引擎。
- 浏览器渲染引擎:通常所说的浏览器内核就是指的浏览器渲染引擎。
- 网络功能模块:通常指的网络线程,开启网络线程,发送请求,下载资源,例如加载静态网页,拿到dom树,css后渲染解析。
- UI后端:则用于绘制基本浏览器的控件,如button,input等元素
- JavaScript解释器:用于浏览器解释执行js,如V8引擎。
- 数据持久化:涉及cookie localStorage sessionStorage 作为前端,可操作性比较少,对于线程完全不可操作,所以重点在于数据持久化,渲染引擎,这两个灵活运用。
目前主流浏览器内核
- Trident内核:Internet Explorer 。360.搜狗浏览器等。
- Gecko内核:Firefox,seaMonkey等。
- Presto内核:Opero<7。
- Webkit内核:Safari,Chrome浏览器。
- Blink内核:其实就是webkit的分支,添加新特性,例如跨进程的iframe,将DOM移入js,提高js对dom访问速度,目前移动端嵌入应用内嵌的浏览器内核开始渐渐使用Blink。
渲染引擎的工作流程,
-
解析HTML构建DOM树,将他解析成树状解构。(可以想成BST二叉树,这个阶段有一个树状的对象。)
-
构建渲染树,根据DOM树每个节点,顺序提取计算使用的css规则,并重新计算DOM树解构的样式图,并且生成一个带有样式表述的DOM树。(可以想成BST二叉树,这个阶段在每个节点加上样式,添加style属性,并更具css规则,添加style里面的规则。)
-
渲染树布局阶段。当渲染树生成结束后,根据每个渲染树节点在页面的位置以及大小。
-
绘制渲染树。将每个dom元素的背景以及颜色等样式信息渲染到节点上面。
这里要关注的是页面的布局阶段和渲染阶段。dom元素如果位置发生改变,就会发生重排=>重绘,如果位置不变,只是样式改变了,就只会发生重绘。重排消耗了巨大的浏览器性能,所以如果要改变位置,请添加position: absolute;.写成绝对定位,尽量减少重排的影响范围。
尼玛这个教程已经深入浅出的将渲染过程讲的很明白了,如果还有问题,建议你去了解BST二叉树结构,至于为什么要了解BTS呢,尼玛整个dom结构都是树状结构,你居然好意思连简单的2叉树都不懂?数据结构与算法这本书有讲。真的不想吐槽,之前看了网络上的劣质教程,说什么将dom树状结构和css样式文件揉成一团,真的被那些个劣质网络教程害了,我迟了半年才懂这个简单的html+css渲染过程。
另外不要再html内容里面的代码插入script,因为他常常会阻塞html解析
1.3搞笑开发流程
编辑器
- sublime 轻, 没有debug 和断点功能
- webStrome 集成面全,可扩展,可断点,
- vscode 轻,支持typescript,可断点调试, 完整性若,
- vim 骨灰级编辑器。用于linux较多
理想中编辑器应具备的能力
- Format能力,规范代码。
- 代码片段Snippet能力,高效开发,emmet
- 自动检错能力,eslint,
- debug,不过大多数浏览器有这个功能。
- git版本控制能力
- 自动文档工具,便于团队协作开发。以及记录,
浏览器调试工具
- chrome
- fiddler
神配合。
第二章 前端与协议
协议无处不在,访问网页http协议,基于https的协议,以及web如何唤起原生app的协议,以及websock协议,与服务器交互Restful协议。协议无处不在,下面细说。
http( HyperText Transport Protocol )超文本协议。
http1.1 长连接 -- keep-alive等头域 http1.1的长连接通过keep-alive的头域信息来控制,而HTTP1.0中,如果要建立,请求信息中包含Connection: keep-alive头域信息返回,值得注意的是,长连接的请求机制并不会节省传输内容的网络开销。
缓存控制
在http1.1之前,浏览器缓存主要通过http1.0的expires头部来控制实现。我们直到expires只能通过绝对时间来刷新缓存,但是http1.1新加入的Cache-Control头域,可以支持相对时间。另外浏览器可以根据Etag和Last-Modified来判断浏览器是否从缓存中加载文件。浏览器发起请求时候,头部域字段的判断流程如下:
- 浏览器会查下Cache-Control是否过期,如果过期如果Cache-Control和Expires同时设置,那么Cache-Control的优先级更高,他是相对过期时间,
- 如果浏览器头部带有Etag,有就带上If-None-Match字段信号,服务器判断Last-Modified失效则返回200,有效就返回304
- 如果Etag和Last-Modified都不存在,则直接向服务器请求内容。
下图就是Cache-Control 和 Etag和Last-Modified请求缓存的主要过程。
部分内容传输优化
部分内容传输优化
http报文内容大全
-
Accept 告诉服务器接受那种媒体类型比如:
accept: application/json
-
Accept-Charset: 浏览器接受的内容的字符集:比如 utf-8
-
Accept-Encoding: 浏览器接受内容的编码方法:比如
Accept-Encoding: gzip, deflate, br
,是否支持压缩压缩方式 -
Accept-Language:浏览器接受的语言类型比如zh-CN
-
Accept-Range: Web服务器一般用于分段传输协议
-
Age: 一般当服务器用自己的缓存实体去响应的时候,可以从该头部表明实体从生产到现在经过了多长时间,比如Age:3600
-
Allow:该头部参数可以设置服务端接受哪些可用的HTTP请求方法。
-
Authorization:当客户端接受来自服务器的www-Authenticate响应的时候,后面可以用该头部来携带自己的身份证来给web服务器认证。
-
Cache-Control:用来声明服务器缓存
- no-cache,不适用实体缓存,从服务器获取内容,
- max-age:只接受Age值小于max-age值的内容,,
- max-stale:可接受过去的对象,但是过期时间必须小于max-stale值。
- min-fresh:接受生命周期大于当前Age跟min-fresh值之和的缓存对象
- publish:可以利用Cache中内容回应任何客户。
- Private:只能用于缓存内容,优先回应先前的内容具体用户。
- no-cache:可以设置那些内容不被缓存
- max-age:设置响应中包含对象的过期时间。
- All:no-storre 不允许缓存
-
Connection:在请求头中,close告诉web服务器或者代理服务器,在完成本次请求后,保持连接,例如keep-alive例如:keep-alive:300。
-
Content-Encoding,与请求头中的accept-Encoding相对应,告诉浏览器web服务器使用哪种方法压缩,gzip,default,
-
Content-Language,告诉浏览器使用哪种语言解析。
-
Content-Length,web服务器告诉浏览器HTTP请求长度
-
Content-Range,响应的文件是哪一部分。
-
Content-type,响应的文件类型,例如:
application/xml
-
Etag:对象的标志,一个对象文件如果被修改了,其Etag也被修改,
-
Expires :web服务器表明实体什么时候过期,对于过期对象,只有在web服务器验证了其有效性后,才响应客户请求。
-
Host:客户端指定自己访问的web服务器域名ip地址或者端口。
-
if-none-match,如果文件包含Etag信息,就会带上if-none-match,
-
if-modified-since:如果上次带有last-modified
-
Location:告诉服务器,新地址
-
Pramga:主要告诉服务器不缓存这个对象
-
Proxy-Authenticate:代理服务器响应浏览器,提供验证信息,
-
Range 要读取的对象
-
Referer 告诉服务器,自己从哪来的。
-
Server:服务器软件版本。
-
User-agent:浏览器代理名称
-
Transfer-Encoding:如何编码
HTTP2
下一个超文本传输协议,首先了解一下http2,spdy加速,他是google发起的,spdy协议要求必须使用https加密传输协议。所以之前http1.1以下的无法使用spdy加速,,因此最终http2决定以spdy为基础,进行开发。http2较之前http1.1有以下区别:
- http2完全采用二进制传输数据,而非http1.x的默认文本格式来传输,二进制的单位一般为帧(一帧包括具有固定格式和长度的二进制数据包),多个帧就形成了网络传输数据流,所以我们理解的http2就是以流为传输数据格式的,,同时HTTP2协议是通过流式传输的,头部采用HPACK压缩传输,最大限度的节省了传输数据带宽,
- http2采用TCP多路复用的方式降低网络请求连接建立和关闭的开销,,多个请求通过一个,相比于http1.x每次请求都会携带大量冗余信息,例如cookie,对此而言,http2就有很大优势了。
这里有必要安利一下我们的基础知识,TCP连接复用和HTTP1.1中的keep-alive连接复用的区别:TCP复用传输是发生在传输层的,而keep-alive控制的文件的连接复用是发生在应用层;keep-alive控制的文件的来连接复用是串行的,即一个文件传输完成后,下一个文件才能用这个连接,而TCP连接是帧的多路复用,这就是说,不同文件的传输帧可以在一个TCP连接中一起使用流式传输。
-
http2支持传输流的优先级和流量控制,HTTP2中每个文件传输流都有自己的传输优先级,并且可以通过服务器改变优先级,动态改变,,例如在未来的服务器,就可以优先保证css优先加载,再加载js文件。
-
支持服务器推送。服务端能再特定条件下把资源主动推送给客户端,就像浏览器端的资源预加载,例如资源推送可以在HTML文档下载之前就让HTML的JavaScript和CSS文件现行下载,,从而大大缩短页面加载和渲染等待时间。
所以基于这些HTTP2的优势,有人提出推广HTTP2,但是目前来说,如果推广http2,那么之前很多网页针对http1.1优化规则就就无效了,而且支持http2的浏览器本身就少,但是http2终将到来,我们却不能立即享有。但是我真的很想说,这些web服务器早就想到了,例如nginx1.13.12,支持http协议在浏览器不支持http2的情况下自动降级。
2.2 web安全机制
web前端安全涵盖很多方面,比如
-
XXS(Cross Site Script, 跨站脚本攻击) 通常由带有页面解析内容的数据未经过处理直接插入页面导致解析错误值得注意的是,XSS分类3种类型,主要区别就是攻击脚本引入位置
- 储存型XSS 攻击脚本常常出现在前端未经处理的提交数据提交保存在数据库,然后再从数据库读取出来后直接插入页面导致。
- 反射型XSS 可能是在网络上url中的url参数中注入了可解析内容的数据导致,如果直接获取URL中不合法插入页面导入
- MXSS(也叫DOM XSS) 渲染dom属性中,将攻击脚本插入dom属性中,被解析导致的,
-
SQL(Structured Query Language, 结构化查询语言) 主要就是因为页面提交数据到服务端后,在服务端未进行数据验证就将数据直接坪街道SQL语句执行,主要方法措施就是在前端输入验证进行严格校验。
-
CSRF(Cross-site Request Forgery,跨站请求伪造) CSRF是指的非源站按照源站点的数据请求格式提交非法数据给源站服务器的一种攻击方式,非源站点在拿到用户登录验证信息的情况下,可以直接对源站点的某个数据接口进行提交。如果源站点对该提交请求的数据来源未经验证,该请求可能被成功执行,这其实不合理。通常比较安全的是通过token(令牌)提交验证的方式来验证请求是否为源站点页面提交的,来阻止跨站伪请求的发生。为了避免跨站请求伪造,通常我们进行token验证,其中一种形式就是将页面到后台验证Token与session临时保存的Token进行比较就可以实现了。
请求劫持与HTTPS
现在除了正常的前后端脚本安全问题,网络请求劫持的发生也越来越频繁。网络劫持一般指网站资源请求过程中因为人为的攻击导致没有加载到预期的资源内容,网络劫持分为2种:DNS劫持和HTTP劫持。
- DNS劫持 简单说就是修改了DNS服务器的关于URL与ip对应关系。
- HTTP劫持 在用户浏览器与访问的目的服务器之间建立的网络数据传输通道中,从网关或者防火墙,这个很诡异,修改了网关层或者防火墙层,监听特定数据,当满足条件时候,在正常数据包中插入或者修改为攻击者设计的网络数据包,目的是让用户浏览解析错误的数据,或者以弹出新框的形式,添加广告,这种预防方法就是使用https协议,来访问目标网站。
HTTPS协议通信过程
HTTPS协议就是通过加入SSL(Secure Sockets Layer)层来加密HTTP数据进行安全传输的HTTP协议,同时启动默认的443端口进行数据传输,那么使用HTTPS是怎样保证浏览器和服务器之间的数据安全呢?先说2个概念:公匙和私匙 他们之间是通过一种加密算法得到的密钥对,即一个公钥配一个密钥,公钥是公开部分,用来会话加密,验证数字签名或者加密可以用相应私钥解密的数据,通过这种算法得到的密钥对保证是唯一的,使用这个密钥的时候,如果其中一个密钥加密一段数据,则必须用另一个密钥解密, 例如三次握手,都是携带密钥进行访问的,下面是node的例子:
const http = require('http');
const https = require('https');
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx) => {
ctx.body = '23';
});
http.createServer(app.callback()).listen(3000);
https.createServer(app.callback()).listen(3001);
RESTful 数据协议规范
path/v2/addBook
第三章,前端3层结构与应用
目前来说,html已经发展到HTML5了,但是在实际开发过程中,html5只有移动端才会用到,虽然出现很多组件开发模式,但是3层结构仍然是基础。
html结构
DOCTYPE,就是他的首部标签,
标签语义化
给予搜索引擎更好的理解,最主要的是杜绝全部由div标签嵌套,
<div class="ui-menu-list">
<div class="menu-list-item"></div>
<div class="menu-list-item"></div>
<div class="menu-list-item"></div>
<div class="menu-list-item"></div>
<div class="menu-list-item"></div>
</div>
<ul class="ui-menu-list">
<li class="menu-list-item"></li>
<li class="menu-list-item"></li>
<li class="menu-list-item"></li>
<li class="menu-list-item"></li>
<li class="menu-list-item"></li>
</ul>
推荐使用header+article+footer的套路
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<header>
</header>
<article>
</article>
<footer>
</footer>
</body>
</html>
即使在没有html的情况下,仍然具备良好的阅读性,例如nav一般存放导航栏结构,article一般存放文章,
- 行内元素:
<a/>, <b/>, <span/>, <img/>,<input/>,<button>,<select>,<strong/>
- 块级元素:
<div/>,<ul/>,<li/>,<dl/>,h1~h6,<p><table>
- 空元素:
<br/>,<hr>,<link><area><base>,<col><command><embed><keygen>
但是这考虑到兼容性问题.
css样式统一化
- reset 这种写法的缺点就是,你所有样式都得自己写
* {
margin: 0;
padding: 0;
}
- normalize,相对于reset存在的问题,遵循某个规范规则,相对于reset而言,normalize,在某些公司前端样式设计规范确定的情况下,可以少写很多样式。
* {
margin: 5px;
padding: 5px;
}
- neat,总的来说就是综合上面两个的优点缺点。 就不多说了。
css预处理工具
SASS预处理主要包括模块引用,嵌套,父级选择器,嵌套属性,注释变量,数据类型,运算,圆括号,函数,攥写,变量默认值,规则指令,控制指令,mixin,继承extend,
表现层动画实现
常见动画方案,也就6种
-
JavaScript直接实现动画, 容易造成页面重排重绘,,性能差,应该尽量避免使用
-
svg动画, 比较复杂,自己去看mdn
-
CSS3transition动画 css3新属性
-
CSS3animation 然而移动端很卡,所以通常添加 transform: translate3D(0,0,0)或者transform: translateZ(0);来开启移动端动画cpu加速,让动画更加流畅。通常就是@keyframes,想想,css动画脱离js,同时可以让浏览器开启cpu加速,实现复杂动画效果,
-
Canvas动画 他也可以实现复杂动画。完全通过JavaScript来控制。
-
requestAnimationFrame 这个不知道
总的来说,pc端,建议直接js动画,或者svg动画实现,移动端建议canvas,css3transition,css3 animation,canvas。
响应式网站
-
方案一: 可以在nodejs端判断访问pc还是移动,动态发布资源。
-
方案二: 例如bootstrap的媒介查询,但是这种方案有以下缺点
- 加载了过多资源。
- 想要做更多差异性功能就比较难了。
- 兼容性问题难以处理。
解决以下问题就好:
- 是否使用同一个站点域名避免跳转的问题,
- 是否能保证移动端加载的资源内容最优。
- 如何做移动端加载资源的最优。
- 如何根据更多的信息进行更加灵活的判断,而不仅仅只是userAgent
如何在判断userAgent
let isMobile = navigator.userAgent.match(/Phone|iPod|Android|iPad/i)
常见优化图片资源,优化,可以选择背景图片的时候,选择不同图分辨率的资源,但是这个不利于seo(Search Engine Optimization )优化,也不能有alt,title等属性,也不能在图片加载失败的时候,显示错误图片,
以 border: 1px; 为例子,在高清屏幕下,会被渲染成2px,可以使用transform: scaleY(1/devicePixelRatio)来实现单方向缩放实现1个像素边框,对于字体,使用transform: scale(.5);来支持小文字。如果页面因为高清屏幕导致显示模糊,那么用 -webkit-font-smoothing: antialiased
来修复。