周末待整理
汇总
项目结构 js-node-java ng
移动端适配 IP6 750 rem
设备像素
屏幕物理像素 任何设备屏幕的物理像素的数量都是固定不变的,单位是pt
css像素 px
https://github.com/riskers/blog/issues/17
https://github.com/riskers/blog/issues/18
延伸 「像素」「渲染像素」以及「物理像素」
display 布局展现
1. none; block;
2. inline <span>
3. inline-block <input>
4. list-item <li>
5. table <table>
6. inline-table
7. table-row-group <tbody>
8. table-header-group <thead>
9. table-footer-group <tfoot>
10. table-row <tr>
11. table-column-group <colgroup>
12. table-column <col>
13. table-cell <td> <th>
14. table-caption <caption>
15. run-in:
16. 旧版本 flexbox 的使用 safari浏览器
box: 块伸缩容器
inline-box: 内联级伸缩容器
17. 混合版本flexbox模型 IE10浏览器 “-ms-”
flexbox:
inline-flexbox:
18. 新版本flexbox模型
flex:
inline-flex:
position static
1. static 文档的常规位置 不会重新定位
2. relative
3. absolute
4. fixed
1-10000的随机数 得到1-10
1-10000 取特定数 取几次 2进制
hybrid 原理。桥 协议 js注入webview
es6多了什么新特性
添加了块级作用域,
一个{}代表一个块级作用,作用域嵌套时外层代码块不受内层代码块的影响,
使得立即执行匿名函数(IIFE)不在必要; IIFE原本的作用是为了形成局部作用域,防止变量污染;
函数本身的作用域,在其所在的块级作用域之内。 es5 存在函数提升,不管函数在何处声明,函数声明都会提升到当前作用域的顶部,得到执行.而es6支持块级作用域,其内部声明的函数皆不会影响到作用域的外部。
增加了语法糖
let命令 所声明的变量,只在let命令所在代码块内有效
- 不会像var一样声明提前,只能在定义之后使用
- 只要作用域内有let声明的变量,这个变量就会被绑定,不受原来变量声明规则的影响。es明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些命令,就会报错ReferenceError。 这在语法上,称为“暂时性死区”。
- 函数的作用域是其声明时所在的作用域
- 不允许在相同作用域内,重复声明同一个变量。因此不能在函数内部重新声明参数。
const命令 用来声明常量, 一旦声明, 常量的值就不能改变
- 对常量重新赋值不会报错,只会默默地失败
- 只在声明所在的块级作用域内有效
- 不存在提升,只能在声明的后面使用,提前使用会抛出ReferenceError
- 不可重复声明
- 只是指向变量所在的地址; 如果将const常量赋值为一个对象,则此常量储存的是一个地址,不可变的只是这个地址,但对象本身是可变的,依然可以为其添加新属性。
全局对象的属性
- 全局对象是最顶层的对象,在浏览器环境指的是window对象, 在Node.js指的是global对象。ES5规定,所有全局变量都是全局对象的属性;ES6规定,var命令和function命令声明的全局变量,属于全局对象的属性; let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。
变量的解构赋值
- 按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称之为解构(Destructing)。解构只能用于数组或对象。其他原始类型的值都是可以转为相应的对象,除了undefined 和null
- 对数组的解构赋值,允许指定默认值。(只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值,set结构也可用)
- 对象的解构,属性没有次序,变量必须与属性同名。 可以很方便地将现有对象的方法,赋值到某个变量。对象的解构同样可以指定默认值,并且可以与函数参数的默认值一起使用。
增加了字符串处理、
字符串处理的增强,字符以utf-16格式储,每个字符固定2个字节。对于那些需要4个字符,js 会认为是两个字符。 es6 增强了对码点大于0xFFFF的字符的整体处理和正则匹配。
- codePointAt() 正确返回四字节的UTF-16字符的 对于常规字符返回结果与 charCodeAt 方法相同
- String.fromCodePoint() 正确返回编号大约0xFFFF码点对应的字符 弥补String.fromCharCode 方法的不足
- at() 返回字符串给定位置的字符,如果该字符的Unicode 编号大于 0xFFFF,可以返回正确的字符。 chatAt()只能返回UTF-16编码的第一个字节,不能正确返回
- 字符的Unicode表示法: "\u{20BB7}"的形式可以正确表示超出\uFFFF的双字节字符
- normalize() String.prototype.normalize()方法。。。
- includes() 返回布尔值,是否找到参数字符串,支持第二个参数,表示开始搜索的位置
- startsWith() 返回布尔值,表示参数字符串是否在源字符串的头部,支持第二个参数,表示开始搜索的位置
- endsWith() 返回布尔值,表示参数字符串是否存在源文件的尾部。支持第二个参数,表示对前N个字符进行搜索
- repeat() 返回一个新字符串,表示将原字符串重复n次
模板字符串
- 增强字符串,用反引号(')标识,普通字符串 多行字符串 字符串中嵌入变量
- 在模板字符串中嵌入变量,需要将变量名写在$()之中
- 反引号 斜杠转义
- 大括号内部可以进行运算, 以及引用对象属性,其中还能调用函数。
- 模板字符串可以紧跟一个函数名后面,该函数将被调用来处理这个模板字符串。函数的参数为模板字符串中没有变量替换的部分组成的数组,第一个参数之后的参数,都是模板字符串各个变量依次被替换后的值, 拥有一个raw属性
数值的扩展
- 二进制和八进制表示法 ??? 0b 0o
- 扩展函数
Number.isFinite()用来检查一个数值是否非无穷(infinity);
Number.isNaN() 用来检查一个值是否为NaN
区别在于传统方法先调用Number(),将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,非数值一律返回false
Number.parseInt()与Number.parseFloat() 将全局方法,移植到Number对象上面,行为完全保持不变
Number.isInteger() 用来判断一个值是否为整数。 在javascript内部,整数和浮点数是同样的储存方法,3和3.0被视为同一个值
Number.isSafeInteger() 则是用来判断一个整数是否落在Number.MAX_SAFE_INTEGER 和Number.MIN_SAFE_INTEGER 这两个常量表示的上下限范围内
Math对象上提供了许多新的数学方法
数组的扩展
- 数组推导:直接通过现有数组生成新数组的一种简化写法, 通过 for...of结构,允许多重循环。 注:新数组会立即在内存中生成,这时如果原数组是一个很大的数组,将会非常耗费内存。
- 数组处理的扩展方法:
- Array.from():用于将两类对象转为真正的数组。类似数组的对象(array-like object)和可遍历(iterable)的对象,其中包括ES6新增的Set和Map结构。 Array.from() 还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理
- Array.of() 用于将一组值,转换为数组。弥补数组构造函数Array()的不足。
- 数组实例的find()用于找出第一个符合条件的数组元素
- 数组实例的findIndex() 用于返回第一个符合条件的数组元素的位置。 这两个方法都可以发现NaN
- 数组实例的fill() 使用给定值 填充一个数组
- 数组实例的entries() 键值对的遍历 ,keys() 针对键名的遍历 和values() 针对键值的遍历, 用于遍历数组,它们都返回一个遍历
对象的扩展
增强的对象写法 允许直接写入变量和函数,作为对象的属性和方法
允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内,允许变量渗入key中
- Object.is() 用来比较两个值是否严格相等。与严格比较浮的不同之处 ,+0不等于-0, NaN等于自身
- Object.assign() 用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两个对象作为参数,第一个是目标对象,后面的参数都是源对象。 同名属性,后面覆盖前面。
- proto属性
用来读取或设置当前对象的prototype对象 - Object.setPrototypeOf()方法的作用与proto相同,用来设置一个对象的prototype对象,是es6正式推荐的设置原型对象的方法
- Object.getPrototypeOf()方法用于读取一个对象的prototype对象
- Symbol原始数据类型,表示独一无二的ID,通过Symbol函数生成。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。Symbol函数可以接受一个字符串作为参数,表示Symbol实例的名称。
- Symbol.keyFor()
- Proxy
用于修改某些操作的默认行为,等于在目标对象之前,架设一层“拦截”,外界对该对象的访问,都必须通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。而 Proxy.revocable()方法则返回一个可取消的Proxy实例。 - Object.observe() Object.unobserve()
Object.observe()方法用来监听对象(以及数组)的变化。一旦监听对象发生变化,就会触发回调函数。
Object.unobserve()方法用来取消监听。- add 添加属性
- update 属性值的变化
- delete 删除属性
- setPrototype设置原型
- reconfigure 属性的attributes 对象发生变化
- preventExtensions 对象被禁止扩展
函数的扩展
- 函数参数默认值 使用=形式
- 指定了默认值之后,函数的length属性,将返回没有指定默认值的参数个数
- 参数默认值所处作用域 是函数作用域 而非全局作用域
- 双重默认值
- rest运算符
- ...变量名:将多余的参数放入一个数组中,rest参数必须为最后一个, 函数的length属性,不包括rest参数
- ... 数组: 将数组转为用逗号分割的参数序列
- 箭头函数
- 函数体内this对象,绑定定义时所在的对象,而不是使用时所在的对象
- 不可以当做构造函数,不可以使用new命令,否则抛出一个错误
- 不可以使用arguments对象,该对象在函数体内不存在
- 尾调用优化:
Set Map数据结构
遍历器(Iterator)
- 一种接口规格; 一是为各种数据结构提供一个统一的 简便的接口,二是使得数据结构的成员能够按某种次序排列
- 调用这个接口,返回一个遍历器对象。 该对象具备next方法,每次调用该方法,会返回一个具有value 和done 两个属性的新对象,指向部署了 Iterator接口的数据结构的一个成员
- for...of 数组 类数组对象 Set Map结构
默认的Iteratorj接口部署在数据结构的Symbol.iterator属性,也就是说调用Symbol.iterator方法,就会得到当前数据结构的默认遍历器 - 调用默认iterator接口的场合:
进行以下操作时,会自动去调用默认iterator接口:
首先是上面介绍的for...of结构;
对数组和Set结构进行解构赋值时,会默认调用iterator接口;
扩展运算符(...)也会调用默认的iterator接口;
yield*
Array.from()
Map(), Set(), WeakMap(), WeakSet()
Promise.all(), Promise.race()
引入generator函数控制函数的内部状态的变化
generator 普通函数
两个特征:
- function命令与函数名之间有一个星号
- 函数体内部使用 yield 语句,定义遍历器的每个成员
- 一个函数的内部状态的遍历器,每调用一次,函数的内部状态发生一次改变
next方法的参数
- yield语句本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数会被当作上一个yield语句的返回值。这个功能有很重要的语法意义,Generator函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过next方法的参数,就有办法在Generator函数开始运行之后,继续向函数体内部注入值。
yield* 语句
- 如果yield 后面跟的是一个遍历器,需要在yield命令后面加上星号。表示返回的是一个遍历器,则遍历有地柜效果 ,如果后面跟的是数组,表示该数组会返回一个遍历器,因此就会遍历数组成员
- 二叉树
Generator函数的应用
- 异步操作同步化
- 控制流管理:yield语句是同步运行,所以多层回调函数可以改写为直线执行的形式。
- 任意对象上部署 iterator 接口
原生提供了Promise对象
- 任务三种状态: 默认(pending) 完成(fulfilled) 失败(rejected)
- 默认状态可以单向转移到完成状态,这个过程叫resolve
- 默认状态可以单向转移到失败装填,这个过程叫reject
- deferred.notify(update)宣告任务执行信息,执行进度; 状态转移是一次性的,一旦任务由初始的pending 转为其他状态,就会进入到下一个任务的执行过程中。
- 是一个构造函数,用来生成Promise实例。 接受函数作参数,resolve()成功 reject()失败
- 实例生成后 用then方法指定resolve方法 reject方法的回调函数; then方法 返回的是新的Promise对象,可以采用链式写法。多个then执行时前一个回调函数完成以后,会将返回结果作为参数,传入后一个回调函数。如果前一个回调函数返回的是Promise对象,这时后一个回调函数就会等待该Promise对象有了运行结果,才会进一步调用。
- Promise.prototype.catch方法是Promise.prototype.then(null, rejection)的别名,用于指定发生错误时的回调函数。
- Promise.all() 将多个Promise实例,包装成一个新的Promise实例。
var p = Promise.all([p1,p2,p3]); 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.race():与Promise.all()形式类似,不同的是只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的返回值。
```
引入了Class(类)的概念,并在语言规格的层面上实现了模块功能
Class “类”, constructor方法表示构造方法,this关键字代表实例对象。
- prototype 在ES6继续存在,除了constructor方法外,类的方法都定义在类的prototype属性上面
- extends关键字,实现继承
- 子类必须在constructor方法中调用super方法,否则新建实例时会报错。
- 如果子类没有定义constructor方法,这个方法会被默认添加
- 在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。
- Class作为构造函数的语法糖,同时有prototype属性和proto属性:
- 子类的proto属性,表示构造函数的继承,总是指向父类。
- 子类prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性。
- 特殊情况:
- 子类继承Object时,子类就是构造函数Object的复制,子类的实例就是Object的实例
- class A{}, Function.prototype A调用后返回一个空对象Object实例 A.prototype.proto指向构造函数Object的prototype属性
- 子类继承null时,相当与一个普通函数直接继承Funciton.prototype,但是子类调用后返回的对象不继承任何方法
Module
-
ES6模块通过export命令显式指定输出的代码,输入时也采用静态命令的形式。
-
取代import语句,整体输入模块作用
-
export default 定义模块的默认方法
-
export * from circle "export *“ 输出circle模块的所有属性和方法 即继承
-
ES6 模块转码
- module transpiler CommonJS模块 AMD模块写法
- SystemJS 可以在浏览器内加载ES6模块 AMD模块 CommonJS模块 将其转为ES5格式
http://imweb.io/topic/55e330d6771670e207a16bbb
https://imququ.com/post/set-map-weakmap-in-es6.html
es6中新增的几种集合类型 Set、Map和WeakMap的区别
set
类数组,成员值唯一 没有重复值
不会发生类型转换,5“5” 内部判断两个值是否不同,类似于精确相等运算(===),例外NaN等于自身
* 属性
Set.prototype.constructor 构造函数 默认是Set函数
Set.prototype.size 返回Set的成员总数
* 方法
add(value) 添加某个值 返回Set结构本身
delete(value) 删除某个值,返回一个布尔值,表示删除是否成功
has(value) 布尔值,是否为Set成员
clear() 清除所有成员,没有返回值
values 返回一个遍历器,set结构的默认遍历器就是它的value方法 可以直接用for...of 循环进行遍历
WeakSet 不重复值结合
与Set区别
* 成员只能是对象; 具有 iterable 接口的对象 eg 数组或者类数组对象
* 对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,如果其他对象不在引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。 用途:储存DOM借点,不用担心这些节点从文档移除时,会引发内存泄漏。
Map结构
类对象 键值对集合, 各种类型的值(包括对象)都可以当作键
Map的键 跟内存地址绑定,内存地址不一样 视为两个键。同名属性碰撞(clash)的问题。
只有对同一个对象的引用,Map结构才将其视为同一个键
* 属性方法
size 返回成员总数
set(key,value) 设置一个键值对
get(key) 读取一个键
has(key) 返回布尔值,键是否在Map数据结构中
delete(key) 删除某个键
clear() 清除所有成员
keys() 键名的遍历器
values() 键值的遍历器
entries() 成员
for...of 遍历 firefox zhichia
WeakMap
只接受对象作为键名(null除外),不接受原始类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制,有助于防止内存泄漏
[https://imququ.com/post/set-map-weakmap-in-es6.html]
es6 promise VS es7 aysnc await
promise
循环执行 callback地狱 then
并发执行 并发执行多个任务时,可以有一个地方回收结果 Promise.all([,]).then(success); count
错误处理 统一用catch处理 promise chain里面出现的错误 callback里面无法用一个try接到深层的error
getUser().then(getArticle).then(success).catch(error);
array reduce 返回 最后一次调用回调函数获得的累积结果。
```
var p = Promise.resolve();
tasks.reduce(function(p, fn) {
return p = p.then(fn);
}, p).then(success);
```
async await 基本上這個語法的目的就是讓程式能再某些想卡住的地方能卡住,但是不是真的卡住,只是種語法糖。
在async function内, 可以用await语法去呼叫另一个async function。
async function里 非同步事件由 promise or generator发起。
另外貼心的一點是 async function 預設會回傳一個 promise,就像 promise api 裡面 then 會幫你做的事一樣,只是搭配 await 以後其實就可以在非同步工作中用 await 語法取代掉 then 讓語法更簡潔。
http https 证书的作用
http
http 缺点 通讯是用明文(不加密),内容可能会被窃听
不验证通信方身份,一次有可能遭遇伪装
无法真名报文的完整性,有可能已经被篡改
https
http+ 加密+认证+完整性保护 = https
-
身披SSL协议的这层外壳的HTTP
-
在采用SSL后, HTTP就拥有了HTTPS的加密, 证书和完整性的保护这些功能.
-
SSL是独立于HTTP的协议, 所有不光是HTTP协议, 其他运行在应用层的SMTP(邮件协议)和Telnet等协议均可配合SSL协议使用. 可以说SSL是当今世界上应用最广泛的网络安全技术.
-
SSL采用公开密钥加密 加密算法公开,密钥是保密的,安全性
-
对称密钥加密/ 共享密钥加密: 加密和解密同用一个密钥的方式
-
将密钥--对方 在互联网转发密钥时,通信被监听 ? 安全转交? 使用两把密钥公开密钥加密
-
非对称密钥 : 一把私有密钥 一把公开密钥; 使用公开密钥加密方式, 发送密文的一方使用对方的公开密钥进行加密处理, 对方收到被加密的信息后, 在使用自己的私有密钥进行解密. 利用这种方式, 不需要发送用来解密的私有密钥, 也不用担心密钥被攻击者窃听而盗走.
-
https混合加密机制,公开密钥加密和共享密钥加密并用的混合加密机制。公开密钥加密和共享密钥加密相比, 其处理速度要慢. 在交换密钥环节适用公开密钥加密方式, 之后的建立通信交换报文阶段则使用共享密钥加密方式.
证明公开密钥的正确性的证书
数字证书认证机构和其他相关机关颁发的公开密钥证书;
- 服务器把自己的公开密钥登录至数字证书认证机构
- 数字证书认证机构用自己的私有密钥向服务器的公开密钥署数字签名并颁发公钥证书
- 客户端拿到服务器的公钥证书后, 使用数字证书认证机构的公开密钥, 向数字证书认证机构验证公钥证书上的数字签名, 以确认服务器的公开密钥的真实性
- 使用服务器的公开密钥对报文加密后发送
- 服务器用私有密钥对报文解
- SSL 服务器客户端双方加密及解密处理 消耗 cpu 资源和内存资源 能够处理的请求数量 必定会随之减少
- 敏感数据 https 购买证书的开销
XSS csrf
XSS “跨站脚本”
注入攻击的一种,不对服务器端造成任何伤害,通过一些站内交互突进 发布评论,太计较还有javascript内容的文本。 服务器端如果没有过滤或转义掉这些脚本,作为内容发布到页面上,用户访问页面会运行脚本。
- 关不掉窗口, 盗号或者其他未授权的操作
- AJAX 不能跨域的初衷也是防范 XSS 。iframe post 请求
- 把所有的用户输入 就进行html转义输出
- 允许用户输入html,又要过滤脚本的 白名单整 使用html解析库遍历借点 获取数据 html比xml有较强的容错性。根据原有标签属性 重新构建html元素树。 所有标签属性从白名单中拿。
- 模板引擎的web项目中,开启默认转义功能。不需要的场合取消,
- 富 AJAX 类应用(例如豆瓣网的阿尔法城)。这类应用的风险并不集中在 HTTP 的静态响应内容,所以不是开启模版自动转义能就能一劳永逸的。再加上这类应用往往需要跨域,开发者不得不自己打开危险的大门。这种情况下,站点的安全非常依赖开发者的细心和应用上线前有效的测试。现在亦有不少开源的 XSS 漏洞测试软件包(似乎有篇文章提到豆瓣网的开发也使用自动化 XSS 测试),但我都没试用过,故不予评价。不管怎么说,我认为从用户输入的地方把好关总是成本最低而又最有效的做法。
CSRF
跨站请求伪造。
伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。
xss XCSRF
- 非get请求
发布帖子这一类创建资源的操作,应该只接受 POST 请求,而 GET 请求应该只浏览而不改变服务器端资源。 - 请求令牌
- “请求令牌”和“同步令牌”原理是一样的,只不过目的不同,后者是为了解决 POST 请求重复提交问题,前者是为了保证收到的请求一定来自预期的页面。实现方法非常简单,首先服务器端要以某种策略生成随机字符串,作为令牌(token),保存在 Session 里。然后在发出请求的页面,把该令牌以隐藏域一类的形式,与其他信息一并发出。在接收请求的页面,把接收到的信息中的令牌与 Session 中的令牌比较,只有一致的时候才处理请求,否则返回 HTTP 403 拒绝请求或者要求用户重新登录验证身份。
- 虽然请求令牌原理和验证码有相似之处,但不应该像验证码一样,全局使用一个 Session Key。因为请求令牌的方法在理论上是可破解的,破解方式是解析来源页面的文本,获取令牌内容。如果全局使用一个 Session Key,那么危险系数会上升。原则上来说,每个页面的请求令牌都应该放在独立的 Session Key 中。我们在设计服务器端的时候,可以稍加封装,编写一个令牌工具包,将页面的标识作为 Session 中保存令牌的键。
- 在 ajax 技术应用较多的场合,因为很有请求是 JavaScript 发起的,使用静态的模版输出令牌值或多或少有些不方便。但无论如何,请不要提供直接获取令牌值的 API。这么做无疑是锁上了大门,却又把钥匙放在门口,让我们的请求令牌退化为同步令牌。
- 第一点说了请求令牌理论上是可破解的,所以非常重要的场合,应该考虑使用验证码(令牌的一种升级,目前来看破解难度极大),或者要求用户再次输入密码(亚马逊、淘宝的做法)。但这两种方式用户体验都不好,所以需要产品开发者权衡。
无论是普通的请求令牌还是验证码,服务器端验证过一定记得销毁。忘记销毁用过的令牌是个很低级但是杀伤力很大的错误。我们学校的选课系统就有这个问题,验证码用完并未销毁,故只要获取一次验证码图片,其中的验证码可以在多次请求中使用(只要不再次刷新验证码图片),一直用到 Session 超时。这也是为何选课系统加了验证码,外挂软件升级一次之后仍然畅通无阻。
webkit渲染原理/渲染树css样式与dom结合/页面优化cdn css放前面js放后面
关键渲染路径
- 创建DOM树
html可以部分执行并显示 - 创建CSSOM树(对附在DOM结构上的样式的一种表示方式)
css是一种渲染阻塞资源, 完全被解析之后才能进入生成渲染树环节
css继承属性,解析完成; css文件适用于当前设备时才能造成阻塞,eg:设备属性
eg - 执行脚本
JavaScript是一种解析阻塞资源(parser blocking resource),它能阻塞HTML页面的解析。
当页面解析到<script>标签,不管脚本是內联的还是外联,页面解析都会暂停,转而加载JavaScript文件(外联的话)并且执行JavaScript。这也是为什么如果JavaScript文件有引用HTML文档中的元素,JavaScript文件必须放在那个元素的后面。
为了避免JavaScript文件阻塞页面的解析,我们可以在<script>标签上添加async属性,使得JavaScript文件异步加载。 - 生成渲染树
渲染树是DOM和CSSOM的结合,是最终能渲染到页面的元素的树形结构表示。也就是说,它包含能在页面中最终呈现的元素,而不包含那些用CSS样式隐藏的元素,比如带有display: none;属性的元素。 - 生成布局
布局决定浏览器视窗大小, 提供上下文依赖的css 样式 eg 百分比或窗口的单位
视口大小由<meta name="viewport" content=“决定”>
如果缺少这个标签 通常默认为 980 - 绘制
页面上可见内容转化为屏幕上的像素点
绘制过程所需花费的时间取决于DOM的大小以及元素的css 样式。。
耗时样式eg: 复杂的渐变背景色 比简单的单色背景 渲染耗时
输入一个url后,会发生什么,一个页面输入后缓存会请求吗? last
页面的请求过程
- 浏览器的URL请求
- 递归寻找DNS服务器
- 接目标IP并建立TCP连接
- 向目标服务器发送http请求
- web服务器接收请求后处理
- web服务器返回相应的结果【无效、重定向、正确页面等】
- 浏览器接收返回的http内容
- 解析html文件,自上而下 先头部 后body
- 解析到头部的css外部链接时,同步去下载, 遇到外部js链接也是下载 【js 顶部 首屏加载时间】
- 解析body 边开始生辰该对应的DOM树 同时等待css 文件下载
- css文件下载完毕,DOM树+CSSOM --》 renderTree
- 渲染树一旦有了结构模型,同步去计算渲染树节点的布局位置
- 一旦计算出来渲染坐标后,同步开始渲染
- 10-13 如果遇到图片则跳过去渲染下面内容,等待图片下载成功后 会返回来在渲染原来图片的位置
- 同14步,如果渲染过程中出现JS代码调整DOM树结构的情况,也会再次重新来过,从修改DOM开始
- 最终所有节点和资源都会渲染完成
- 渲染完成后开始page的onload时间
- 整个页面load完成
整个过程中会有很多的分别请求,所以TCP连接会很多,并且每一个用完都会自己关了,除非是keep-live类型的可以请求多次才关闭。
https://yq.aliyun.com/articles/20667
web前端优化规则
减少 http 请求
合并脚本跟样式文件,如可以把多个css文件合成一个,把多个JS文件合成一个。
CSS Sprites利用css background相关元素进行背景图的绝对定位,把多个图片合成一个图片
使用浏览器缓存
在用户浏览网站的不同页面时,很多内容是重复的,比如相同的JS、CSS、图片等。 强制浏览器在本地缓存这些文件,将大大降低页面产生的流量,从而降低页面载入时间。
根据服务器端的响应header,一个文件对浏览器而言,有几级不同的缓存状态。
- 服务器端告诉浏览器不要缓存此文件,每次都到服务器上更新文件
- 服务器端没有给浏览器任何指示
- 在上次传输中,服务器给浏览器发送了Last-Modified或Etag数据,再次浏览时浏览器将提交这些数据到服务器,验证本地版本是否最新的,如果为最新的则服务器返回304代码,告诉浏览直接使用本地版本,否则下载新版本。一般来说有且只有静态文件,服务器端才会给出这些数据。
- 服务器强制要求浏览器缓存文件,并设置了过期时间。在缓存未到期之前,浏览器将直接使用本地缓存文件,不会与服务器端产生任何通信。
尽量强制浏览器到第四种状态,特别是对于 JS、CSS、图片等变动较少的文件。
使用压缩组件
IE和Firefox浏览器都支持客户端GZIP,传输之前,先使用GZIP压缩再传输给客户端,客户端接收之后由浏览器解压,这样虽然稍微占用了一些服务器和客户端的CPU,但是换来的是更高的带宽利用率。对于纯文本来讲,压缩率是相当可观的。如果每个用户节约50%的带宽,那么租用来的那点带宽就可以服务多一倍的客户,并且缩短了数据的传输时间。
图片、JS的预载入
JS中实例化一个新的Image(),
将脚本放在底部
脚本放在顶部带来的问题:
- 使用脚本时,对于位于脚本以下的内容,逐步呈现将被阻塞
- 在下载脚本时会阻塞并行下载
将样式文件放在页面顶部
- 白屏
- 无样式内容闪烁
使用外部的JS和CSS
将内联的做成外部的 减少重复下载内联的JS 和CSS
切分组件到多个域
主要的目的是提高页面组件并行下载能力. 但不要跨太多域名,建议采用2个域名。 img1.qunar。com img2.qunar.com
精简JS
- 精简:从代码中移除不必要的字符以减少其大小
- 混淆:在精简的同时,还会改写代码、函数、变量名被转换成更短的字符串
可以使用ShrinkSafe来精简JS http://shrinksafe.dojotoolkit.org/
精简CSS
从代码中移除不必要的字符以减少其大小
可以使用CSS Compressor http://www.cssdrive.com/index.php/main/csscompressor /
精简图片、Flash
对大图片、Flash,要在效果和大小之前做出平衡