动画性能(二)

水了好几天的日记了,居然忘了最重要的YY环节…

动画帧和帧率

动画是由一帧一帧构成的。帧可以理解为是动画过程的一张张照片。
动画的性能(视觉上的卡顿程度)与帧率有关,也就是1s钟内有多少帧。60fps表示1s钟有60帧。
我们一般使用的显示器刷新率是60Hz,也就是1s钟刷新60次。对于人眼来说就是1s钟看到了60张照片,由于人眼的视觉暂留使得两张照片得以连贯过渡,从而形成动画。说成帧率的话也就是60fps,因而60fps是所有web动画追求的极致。
通常来说动画如果低于30fps将无法接受。强调动画性能在某种程度上就是获得更高的帧率。

帧绘制

那么在web中,每一帧的绘制流程是怎样的呢?

  1. javascript执行(function call)
  2. 计算需要被加载到节点上的样式结果(Recalculate style–样式重计算)
  3. 为每个节点生成图形和位置(Layout–回流和重布局)
  4. 将每个节点填充到图层中(Paint Setup和Paint–重绘)
  5. 组合图层到页面上(Composite Layers–图层重组)

frame-flow
动画性能优化的核心也就是缩小每帧绘制所需要的时间,尽量在1/60s内完成,从而达到60fps
上面的步骤有些是可以省略的,优化点就是去省略或者压缩每个点所需的时间。
如变换( transform )和透明度( opacity )的改变就不会触发2、3、4过程。

动画性能(一)

作为一个前端,没有流畅的动画的话,那只能是个切图的…直入主题了,好困的…

图层

用过PS的切图仔肯定知道射鸡师们给出的psd是由一个个图层组成的。不过不知道你是否留意到,你所写的前端页面也是由一个个图层堆叠而成的。
浏览器在渲染一个页面时,会将页面分为很多个图层,图层有大有小,每个图层上有一个或多个节点。
在渲染DOM的时候,浏览器所做的工作实际上是:

  1. 获取DOM后分割为多个图层
  2. 对每个图层的节点计算样式结果(Recalculate style–样式重计算)
  3. 为每个节点生成图形和位置(Layout–回流和重布局)
  4. 将每个节点绘制填充到图层位图中(Paint Setup和Paint–重绘)
  5. 图层作为纹理上传至GPU
  6. 符合多个图层到页面上生成最终屏幕图像(Composite Layers–图层重组)

Chrome子开发者工具台中勾选“show layer borders”标记(在 “rendering” 标题下),它会高亮屏幕上的层。

图层创建的标准

下面为chrome启发式创建图层的条件:

  • 3D 或透视变换(perspective transform) CSS 属性
  • 使用加速视频解码的 <video> 元素
  • 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 <canvas> 元素
  • 混合插件(如 Flash)
  • 对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

需要注意的是,如果图层中某个元素需要重绘,那么整个图层都需要重绘。

参考文献

javascript中的数据类型判断

靠,周末比平时还累,好不容易补完了昨天的一篇…看来今天又要水一篇了😭。

typeof

类型 结构
Undefined undefined
Null object (😣)
布尔值 boolean
数值 number
字符串 string
Symbol (ECMAScript 6 新增) symbol
函数对象 (implements [[Call]] in ECMA-262 terms) function
任何其他对象 object

能认识的就这么多了,君看着办吧

instanceof

注意了这货不能跨环境,如多个frame或window。

1
object instanceof constructor

我们玩个真心话大冒险吧,你随便问,不过我只能回答“是”或者“否”,你开始吧

toString()

猪脚上传…🐷…长相很一般吗…

Object in ES5

Object.create(proto[, descriptors])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 指定原型创建空对象
Object.create(proto)
// 指定原型和属性秒速来创建一个对象
Object.create(proto, descriptors)
// example
var obj = Object.create({x: 1}, {
z: {
value: 3,
writable: true,
enumerable: true,
configurable:true
}
});

属性描述

1
2
3
4
5
6
{
value: 3, // 属性值
writable: true, // 属性是否可写, 默认为false
enumerable: true, // 属性是否可枚举, 默认为false [当使用for/in语句时,该property是否会被枚举]
configurable: true // 属性是否可配置, 默认为false [该property的属性是否可以修改(如由不可写改为可写),property是否可以删除]
}

使用 obj.a = 123; 创建的属性writable, enumerable, configurable属性均为true

1
2
3
4
5
6
7
8
9
10
11
12
13
// 拥有getter和setter的属性是否可读写取决于是否有get和set函数,因此没有value和writable属性
{
get: function(){...},
set: function(){...},
enumerable: true,
configurable: true
}
// example
var o ={
$n : 5,
get next(){return this.$n++;},
set next(n) {this.$n = n;}
};

Generator Basics

首先来看一端js代码。

1
2
3
4
5
6
7
8
9
10
11
});
});
});
});
});
});
});
});
});
});
});

是不是很眼熟呢?没错,不要怀疑,或多或少,或大或小的都存在这样的代码吧。
异步编程是js的核心思想,ES6之前Javascript异步编程的4种方法

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise对象

ES6的Generator将JavaScript异步编程带入了一个全新的阶段,ES7的Async函数更是提出了异步编程的终极解决方案。

pm2基础命令

他跟PM2.5扯不上任何关系,也不是Project Management,pm2是一个带有负载均衡功能的Node应用的进程管理器。可轻松根据服务器CPU fork出多个进程,并保证永远存活,自动重启。目前已在生产环境被普遍使用。

安装

1
npm install -g pm2

常用命令

1
2
3
4
5
6
7
8
9
pm2 start app.js [-i 4] # 托管运行app.js, 可通过-i指定进程数,也可传递'-i max'
pm2 start app.js --name app # 命名启动进程
pm2 list # 显示所有进程状态
pm2 monit # 监视所有进程的资源使用状况
pm2 logs # 显示所有进程日志
pm2 stop [all | name | id] # 停止全部或者指定name或id的进程
pm2 restart [all | name | id] # 重启全部或者指定name或id的进程
pm2 reload [all | name |id] # 0秒停机重载进程
pm2 delete [all | name |id] # 删除全部或者指定name或id的进程

日志

pm2会接管项目日志默认存放于用户目录下

1
~/.pm2/logs/

日志文件明构成:

  • 错误日志:{appName}-error-{id}.log
  • 其他日志:{appName}-out-{id}.log

注意:使用 pm2 logs 可实时查看所有进程日志。