Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63e2ca4d0d | ||
|
|
9dbd1fb7b9 | ||
|
|
7d8816c2c2 | ||
|
|
44ae420f52 | ||
|
|
683b22d1ae | ||
|
|
4e58379585 | ||
|
|
1342144fef | ||
|
|
a41f452df0 | ||
|
|
0950c4cdaf | ||
|
|
46ad26c1a4 | ||
|
|
6dd26bee54 | ||
|
|
37d6b5f3f0 | ||
|
|
f23e88338f | ||
|
|
3dda46d760 | ||
|
|
cd6a00bf3a | ||
|
|
6aad1da704 | ||
|
|
03a5a0f484 | ||
|
|
0066b890d4 | ||
|
|
e0caf77d0a | ||
|
|
1517e86999 | ||
|
|
c8f86df3f3 | ||
|
|
752d598d27 | ||
|
|
e5fd022f00 | ||
|
|
f78c4fb511 | ||
|
|
41a90e5991 | ||
|
|
a4efe24cca | ||
|
|
1a3b36074e | ||
|
|
8dad4956b7 | ||
|
|
852d35501c | ||
|
|
b9d95182a1 | ||
|
|
bfa3ab7b55 | ||
|
|
304e4d3aa3 | ||
|
|
62be743112 | ||
|
|
6d27e723cd | ||
|
|
704c9cda9e | ||
|
|
44dd8057e2 | ||
|
|
d956b15ad0 | ||
|
|
961d77b4d1 | ||
|
|
c763fc15bd | ||
|
|
f9f04d711f | ||
|
|
5d40208d45 | ||
|
|
771bb9f914 | ||
|
|
96f850e29f | ||
|
|
349e7df2b6 | ||
|
|
b198d57cf6 | ||
|
|
03b8840291 | ||
|
|
60899c0bf8 | ||
|
|
648e113e66 | ||
|
|
61a5e74908 | ||
|
|
d2273e72f6 | ||
|
|
386b605c32 | ||
|
|
b60cca25d7 | ||
|
|
68e6c23f82 | ||
|
|
a9d2c1d47a | ||
|
|
cc364c4b2f | ||
|
|
f65b11ea6b | ||
|
|
35458365c6 | ||
|
|
dde997ac27 | ||
|
|
53ae9e077e | ||
|
|
30bdcf13dd | ||
|
|
12b1b02539 | ||
|
|
2a92487a5e | ||
|
|
b6487f8754 | ||
|
|
7a8e1b25dd | ||
|
|
44683fa1dc | ||
|
|
3a4b82bc76 | ||
|
|
4f2ed7b3cb | ||
|
|
a72795b099 | ||
|
|
dea2acc384 | ||
|
|
74f539cc34 | ||
|
|
1947b9c08c | ||
|
|
e84c85cc1d | ||
|
|
170c0f4525 | ||
|
|
c836848228 | ||
|
|
7b87d5c3c4 | ||
|
|
add5bdd01e | ||
|
|
0633764a44 | ||
|
|
fcc183d523 | ||
|
|
627db8a249 | ||
|
|
b41530b37c | ||
|
|
2062b652dd | ||
|
|
365997863e | ||
|
|
ab6978da4a | ||
|
|
f37d496f1b | ||
|
|
3bf34602b4 | ||
|
|
274ffc0a9f | ||
|
|
72e8b69dd7 | ||
|
|
62ac1d76b9 | ||
|
|
e537efe7bd | ||
|
|
f1871f59e5 | ||
|
|
5d08eabde3 | ||
|
|
7e79c60a12 | ||
|
|
9c051f6ab5 | ||
|
|
065fab1546 | ||
|
|
88cd38685d | ||
|
|
7de3c77c3b | ||
|
|
09978602c0 | ||
|
|
fcb42f2dcf | ||
|
|
0ef3cf16a9 | ||
|
|
baf666dbf8 | ||
|
|
74f1884f78 | ||
|
|
4f815df5ab | ||
|
|
35a8ee0a9e | ||
|
|
37fbb981d4 | ||
|
|
1cd6722352 | ||
|
|
e14a9e8f9b | ||
|
|
f3e2892982 | ||
|
|
bd8c58a938 |
@@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
/yarn.lock
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"excludeFiles": [],
|
||||
"rules": {
|
||||
"no-long-code": 0,
|
||||
"no-trailing-punctuation": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "10"
|
||||
before_install:
|
||||
- npm i -g lint-md-cli
|
||||
script: lint-md ./
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<img src="assets/1/cube.jpeg" alt="logo" width="500" />
|
||||
|
||||
> 如今,Javascript 模块化规范非常方便、自然,但这个新规范仅执行了2年,就在 4 年前,js 的模块化还停留在运行时支持,10 年前,通过后端模版定义、注释定义模块依赖。对经历过来的人来说,历史的模块化方式还停留在脑海中,反而新上手的同学会更快接受现代的模块化规范。
|
||||
> 如今,Javascript 模块化规范非常方便、自然,但这个新规范仅执行了 2 年,就在 4 年前,js 的模块化还停留在运行时支持,10 年前,通过后端模版定义、注释定义模块依赖。对经历过来的人来说,历史的模块化方式还停留在脑海中,反而新上手的同学会更快接受现代的模块化规范。
|
||||
|
||||
但为什么要了解 Javascript 模块化发展的历史呢?因为凡事都有两面性,了解 Javascript 模块化规范,有利于我们思考出更好的模块化方案,纵观历史,从 1999 年开始,模块化方案最多维持两年,就出现了新的替代方案,比原有的模块化更清晰、强壮,我们不能被现代模块化方式限制住思维,因为现在的 ES2015 模块化方案距离发布也仅仅过了两年。
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
**外部依赖定义 (2007)**: 这种定义方式在 cocos2d-js 开发中普遍使用,其核心思想是将依赖抽出单独文件定义,这种方式不利于项目管理,毕竟依赖抽到代码之外,我是不是得两头找呢?所以才有通过 webpack 打包为一个文件的方式暴力替换为 commonjs 的方式出现。
|
||||
|
||||
**Sandbox模式 (2009)**: 这种模块化方式很简单,暴力,将所有模块塞到一个 `sanbox` 变量中,硬伤是无法解决明明冲突问题,毕竟都塞到一个 `sandbox` 对象里,而 `Sandbox` 对象也需要定义在全局,存在被覆盖的风险。模块化需要保证全局变量尽量干净,目前为止的模块化方案都没有很好的做到这一点。
|
||||
**Sandbox 模式 (2009)**: 这种模块化方式很简单,暴力,将所有模块塞到一个 `sandbox` 变量中,硬伤是无法解决命名冲突问题,毕竟都塞到一个 `sandbox` 对象里,而 `Sandbox` 对象也需要定义在全局,存在被覆盖的风险。模块化需要保证全局变量尽量干净,目前为止的模块化方案都没有很好的做到这一点。
|
||||
|
||||
**依赖注入 (2009)**: 就是大家熟知的 angular1.0,依赖注入的思想现在已广泛运用在 react、vue 等流行框架中。但依赖注入和解决模块化问题还差得远。
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
这篇文章所提供的模块化历史的方案都是逻辑模块化,**从 CommonJS 方案开始前端把服务端的解决方案搬过来之后,算是看到标准物理与逻辑统一的模块化**。但之后前端工程不得不引入模块化构建这一步。正是这一步给前端开发无疑带来了诸多的不便,尤其是现在我们开发过程中经常为了优化这个工具带了很多额外的成本。
|
||||
|
||||
从 CommonJS 之前其实都只是封装,并没有一套模块化规范,这个就有些像类与包的概念。我在10年左右用的最多的还是 YUI2,YUI2 是用 namespace 来做模块化的,但有很多问题没有解决,比如多版本共存,因此后来 YUI3 出来了。
|
||||
从 CommonJS 之前其实都只是封装,并没有一套模块化规范,这个就有些像类与包的概念。我在 10 年左右用的最多的还是 YUI2,YUI2 是用 namespace 来做模块化的,但有很多问题没有解决,比如多版本共存,因此后来 YUI3 出来了。
|
||||
|
||||
```javascript
|
||||
YUI().use('node', 'event', function (Y) {
|
||||
@@ -118,7 +118,7 @@ YUI3 的 sandbox 像极了差不多同时出现的 AMD 规范,但早期 yahoo
|
||||
### 补充阅读
|
||||
|
||||
- [JavaScript 模块化七日谈](https://huangxuan.me/2015/07/09/js-module-7day/)
|
||||
- [JavaScript模块化编程简史(2009-2016)](https://yuguo.us/weblog/javascript-module-development-history/)
|
||||
- [JavaScript 模块化编程简史(2009-2016)](https://yuguo.us/weblog/javascript-module-development-history/)
|
||||
|
||||
# 总结
|
||||
|
||||
@@ -136,4 +136,4 @@ YUI3 的 sandbox 像极了差不多同时出现的 AMD 规范,但早期 yahoo
|
||||
|
||||
至此,对于 javascript 模块化讨论已接近尾声,对其优缺点也基本达成了一致。前端复杂度不断提高,促使着模块化的改进,代理(浏览器、node) 的支持程度,与前端特殊性(流量、缓存)可能前端永远也离不开构建工具,新的标准会让这些工作做的更好,同时取代、增强部分特征,前端的未来是更加美好的,复杂度也更高。
|
||||
|
||||
**如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。**
|
||||
**如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。**
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
### 可访问性的反思
|
||||
|
||||
Accessibility 翻译过来是『无障碍访问』,是对不同终端用户的体验完善。每一个模态框,都要有通过键盘关闭的功能,通常使用ESC键。似乎我们程序员多少总会把我们自我的惯性思维带进实现的产品,尤其是当我们敲着外置的键盘,用着 PC 的时候。
|
||||
Accessibility 翻译过来是『无障碍访问』,是对不同终端用户的体验完善。每一个模态框,都要有通过键盘关闭的功能,通常使用 ESC 键。似乎我们程序员多少总会把我们自我的惯性思维带进实现的产品,尤其是当我们敲着外置的键盘,用着 PC 的时候。
|
||||
|
||||
下面的这些问题都是对可访问性的反思:
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
**前端渲染的优势**
|
||||
|
||||
- 局部刷新。无需每次都进行完整页面请求
|
||||
- 懒加载。如在页面初始时只加载可视区域内的数据,滚动后rp加载其它数据,可以通过 react-lazyload 实现
|
||||
- 懒加载。如在页面初始时只加载可视区域内的数据,滚动后 rp 加载其它数据,可以通过 react-lazyload 实现
|
||||
- 富交互。使用 JS 实现各种酷炫效果
|
||||
- 节约服务器成本。省电省钱,JS 支持 CDN 部署,且部署极其简单,只需要服务器支持静态文件即可
|
||||
- 天生的关注分离设计。服务器来访问数据库提供接口,JS 只关注数据获取和展现
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
本次提出独到观点的同学有:[@javie007](http://link.zhihu.com/?target=https%3A//github.com/javie007) [@杨森](https://www.zhihu.com/people/c93b7957f6308990c7e3b16103c9356b) [@流形](https://www.zhihu.com/people/6c772f9726a914ed4a4b90c88010461c) [@camsong](https://www.zhihu.com/people/078cc0fb15845759ad8295b0f0e50099) [@Turbe Xue](https://www.zhihu.com/people/turbe-xue) [@淡苍](https://www.zhihu.com/people/5ac53c9c0484e83672e1c1716bdf0ff9) [@留影](https://www.zhihu.com/people/38c3c75795824de1bc5d99cff904a832) [@FrankFang](http://link.zhihu.com/?target=https%3A//github.com/FrankFang) [@alcat2008](http://link.zhihu.com/?target=https%3A//github.com/alcat2008) [@xile611](http://link.zhihu.com/?target=https%3A//github.com/xile611) [@twobin](http://link.zhihu.com/?target=https%3A//github.com/twobin) [@黄子毅](https://www.zhihu.com/people/3ec85a04bc9eaa35b1830874cc463a52) 精读由此归纳。
|
||||
|
||||
大家对前端和后端渲染的现状基本达成共识。即前端渲染是未来趋势,但前端渲染遇到了首屏性能和SEO的问题。对于同构争议最多,在此我归纳一下。
|
||||
大家对前端和后端渲染的现状基本达成共识。即前端渲染是未来趋势,但前端渲染遇到了首屏性能和 SEO 的问题。对于同构争议最多,在此我归纳一下。
|
||||
|
||||
### 前端渲染遇到的问题
|
||||
|
||||
@@ -46,7 +46,7 @@ SEO 很好理解。由于传统的搜索引擎只会从 HTML 中抓取数据,
|
||||
|
||||
### 同构的优点
|
||||
|
||||
同构恰恰就是为了解决前端渲染遇到的问题才产生的,至 2014 年底伴随着 React 的崛起而被认为是前端框架应具备的一大杀器,以至于当时很多人为了用此特性而[放弃 Angular 1 而转向 React](http://link.zhihu.com/?target=https%3A//blog.risingstack.com/from-angularjs-to-react-the-isomorphic-way/)。然而近3年过去了,很多产品逐渐从全栈同构的理想化逐渐转到首屏或部分同构。让我们再一次思考同构的优点真是优点吗?
|
||||
同构恰恰就是为了解决前端渲染遇到的问题才产生的,至 2014 年底伴随着 React 的崛起而被认为是前端框架应具备的一大杀器,以至于当时很多人为了用此特性而[放弃 Angular 1 而转向 React](http://link.zhihu.com/?target=https%3A//blog.risingstack.com/from-angularjs-to-react-the-isomorphic-way/)。然而近 3 年过去了,很多产品逐渐从全栈同构的理想化逐渐转到首屏或部分同构。让我们再一次思考同构的优点真是优点吗?
|
||||
|
||||
1. 有助于 SEO
|
||||
|
||||
@@ -65,7 +65,7 @@ SEO 很好理解。由于传统的搜索引擎只会从 HTML 中抓取数据,
|
||||
|
||||
1. 性能
|
||||
|
||||
把原来放在几百万浏览器端的工作拿过来给你几台服务器做,这还是花挺多计算力的。尤其是涉及到图表类需要大量计算的场景。这方面调优,可以参考 [walmart的调优策略](https://medium.com/walmartlabs/reactjs-ssr-profiling-and-caching-5d8e9e49240c)。
|
||||
把原来放在几百万浏览器端的工作拿过来给你几台服务器做,这还是花挺多计算力的。尤其是涉及到图表类需要大量计算的场景。这方面调优,可以参考 [walmart 的调优策略](https://medium.com/walmartlabs/reactjs-ssr-profiling-and-caching-5d8e9e49240c)。
|
||||
|
||||
个性化的缓存是遇到的另外一个问题。可以把每个用户个性化信息缓存到浏览器,这是一个天生的分布式缓存系统。我们有个数据类应用通过在浏览器合理设置缓存,双十一当天节省了 70% 的请求量。试想如果这些缓存全部放到服务器存储,需要的存储空间和计算都是很非常大。
|
||||
|
||||
@@ -97,7 +97,7 @@ export const isSsr = () => (
|
||||
|
||||
5. simple store(redux)
|
||||
|
||||
这个 store 是必须以字符串形式塞到前端,所以复杂类型是无法转义成字符串的,比如function。
|
||||
这个 store 是必须以字符串形式塞到前端,所以复杂类型是无法转义成字符串的,比如 function。
|
||||
|
||||
总的来说,同构渲染实施难度大,不够优雅,无论在前端还是服务端,都需要额外改造。
|
||||
|
||||
@@ -136,7 +136,7 @@ Next.js 是时下非常流行的基于 React 的同构开发框架。作者之
|
||||
|
||||
1. 巧妙地用标准化的解决了请求的问题。同构和页面开发类似,异步是个大难题,异步中难点又在接口请求。Next.js 给组件新增了 getInitialProps 方法来专门处理初始化请求,再也不用手动往页面上塞 DATA 和调用 ReactDOMServer.renderToString
|
||||
2. 使用 [styled-jsx](https://github.com/zeit/styled-jsx) 解决了 css-in-js 的问题。这种方案虽然不像 styled-component 那样强大,但足够简单,可以说是最小的成本解决了问题
|
||||
3. Fast by default。页面默认拆分文件方式打包,支持Prefetch页面预加载
|
||||
3. Fast by default。页面默认拆分文件方式打包,支持 Prefetch 页面预加载
|
||||
|
||||
全家桶式的的解决方案。简洁清晰的目录结构,这一点 Redux 等框架真应该学一学。不过全家桶的方案比较适合全新项目使用,旧项目使用要评估好成本
|
||||
|
||||
@@ -164,11 +164,11 @@ async function mount() {
|
||||
|
||||
```javascript
|
||||
async function mount() {
|
||||
const result = await Promise.all(
|
||||
const result = await Promise.all([
|
||||
fetch('a.json'),
|
||||
fetch('b.json'),
|
||||
fetch('c.json')
|
||||
);
|
||||
]);
|
||||
|
||||
render(...result);
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
3. 局部与全局状态的归一
|
||||
4. 分形思想
|
||||
5. action 分散执行
|
||||
5. app级别数据处理,推荐前端 `Orm`
|
||||
5. app 级别数据处理,推荐前端 `Orm`
|
||||
|
||||
整体来看,核心思路是推荐组件内部完成数据流的处理,不用关心使用了 `Redux` `Mobx` 或者 `Rxjs`,也不用关心这些库是否有全局管理的野心,如果全局管理那就挂载到全局,但组件内部还是局部管理。
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
以 Mobx 为代表,轻前端用的较多,因为复杂度集中在后端,前端做好数据展示即可,那么直接拥抱 js 这种基于对象的语言,结合原生 `Map` `Proxy` `Reflect` 将副作用进行到底,开发速度快得飞起。
|
||||
|
||||
数据存储方式按照视图形态来,因为视图之间几乎毫无关联,而且特别是数据产品,后端数据量巨大,把数据处理过程搬到前端是不可能的(为了推导出一个视图形态数据,需要动辄几GB的原始数据运算,存储和性能都不适合在前端做)。
|
||||
数据存储方式按照视图形态来,因为视图之间几乎毫无关联,而且特别是数据产品,后端数据量巨大,把数据处理过程搬到前端是不可能的(为了推导出一个视图形态数据,需要动辄几 GB 的原始数据运算,存储和性能都不适合在前端做)。
|
||||
|
||||
#### 函数式
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
### 分形的缺点
|
||||
|
||||
对于聊天室或者在线IDE等,全局数据居多,很多交叉绑定的情况,就不适合分形思想,反而纯 Redux 思想更合适。
|
||||
对于聊天室或者在线 IDE 等,全局数据居多,很多交叉绑定的情况,就不适合分形思想,反而纯 Redux 思想更合适。
|
||||
|
||||
## 3.3 数据形态,是原始数据还是视图数据?
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
Stack 部分主要在阐明 js 中函数调用栈的概念,它符合栈的基本特性『当调用时,压入栈顶。当它执行完毕时,被弹出栈』,简单看下面的代码:
|
||||
|
||||
```
|
||||
```plain
|
||||
function c() {
|
||||
try {
|
||||
var bar = baz;
|
||||
@@ -46,7 +46,7 @@ a();
|
||||
|
||||
## 如何使用堆栈追踪
|
||||
|
||||
该部分以 NodeJS 环境为例,讲解了 `Error.captureStackTrace `,将 stack 信息作为属性存储在一个对象当中,同时可以过滤掉一些无用的堆栈信息。这样可以隐藏掉用户不需要了解的内部细节。作者也以 Chai 为例,内部使用该方法对代码的调用者屏蔽了不相关的实现细节。通过以 Assertion 对象为例,讲述了具体的内部实现,简单来说通过一个 addChainableMethod 链式调用工具方法,在运行一个 Assertion 时,将它设为标记,其后面的堆栈会被移除;如果 assertion 失败移除起后面所有内部堆栈;如果有内嵌 assertion,将当前 assertion 的方法放到 ssfi 中作为标记,移除后面堆栈帧;
|
||||
该部分以 NodeJS 环境为例,讲解了 `Error.captureStackTrace`,将 stack 信息作为属性存储在一个对象当中,同时可以过滤掉一些无用的堆栈信息。这样可以隐藏掉用户不需要了解的内部细节。作者也以 Chai 为例,内部使用该方法对代码的调用者屏蔽了不相关的实现细节。通过以 Assertion 对象为例,讲述了具体的内部实现,简单来说通过一个 addChainableMethod 链式调用工具方法,在运行一个 Assertion 时,将它设为标记,其后面的堆栈会被移除;如果 assertion 失败移除起后面所有内部堆栈;如果有内嵌 assertion,将当前 assertion 的方法放到 ssfi 中作为标记,移除后面堆栈帧;
|
||||
|
||||
# 3. 精读
|
||||
参与本次精读的同学有:[范洪春](https://www.zhihu.com/people/fanhc/activities)、[黄子毅](https://www.zhihu.com/people/huang-zi-yi-83/answers)、[杨森](https://www.zhihu.com/people/yangsen/answers)、[camsong](https://www.zhihu.com/people/camsong/answers),该部分由他们的观点总结而出。
|
||||
@@ -83,7 +83,7 @@ describe('should.js和power-assert的区别', () => {
|
||||
|
||||
- 区分操作异常和程序员的失误。操作异常指可预测的不可避免的异常,如无法连接服务器
|
||||
- 操作异常应该被处理。程序员的失误不需要处理,如果处理了反而会影响错误排查
|
||||
- 操作异常有两种处理方式:同步 (try…catch) 和异步(callback, event - emitter)两种处理方式,但只能选择其中一种。
|
||||
- 操作异常有两种处理方式:同步 (try……catch) 和异步(callback, event - emitter)两种处理方式,但只能选择其中一种。
|
||||
- 函数定义时应该用文档写清楚参数类型,及可能会发生的合理的失败。以及错误是同步还是异步传给调用者的
|
||||
- 缺少参数或参数无效是程序员的错误,一旦发生就应该 throw。
|
||||
传递错误时,使用标准的 Error 对象,并附件尽可能多的错误信息,可以使用标准的属性名
|
||||
@@ -81,7 +81,7 @@ react-css-modules 引入了 styleName,将本地变量和全局变量很清晰
|
||||
|
||||
另外,使用 react-css-modules,可以方便的覆盖本地变量的样式:
|
||||
|
||||
```
|
||||
```plain
|
||||
import customStyles from './table-custom-styles.css';
|
||||
|
||||
<Table styles={customStyles} />;
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
# 2 内容概要
|
||||
|
||||
使用 Object.assign 作用于大对象时,速度会成为瓶颈,比如拥有 `100,000` 个属性的对象,这个操作耗费了 134ms。性能损失主要原因是 “结构共享” 操作需要遍历近10万个属性,而这些引用操作耗费了100ms以上的时间。
|
||||
使用 Object.assign 作用于大对象时,速度会成为瓶颈,比如拥有 `100,000` 个属性的对象,这个操作耗费了 134ms。性能损失主要原因是 “结构共享” 操作需要遍历近 10 万个属性,而这些引用操作耗费了 100ms 以上的时间。
|
||||
|
||||
解决办法就是减少引用指向的操作数量,而且由于引用指向到任何对象的损耗都几乎一致(无论目标对象极限小或者无穷大,引用消耗时间都几乎没有区别),我们需要一种精心设计的树状结构将打平的引用建立深度,以减少引用操作次数,`vector tries` 就是一种解决思路:
|
||||
|
||||
@@ -7,29 +7,29 @@
|
||||
|
||||
我为什么要选这篇文章呢?
|
||||
|
||||
就在前几天的 Google I/O 2017上, Polymer 正式发布了 [Polymer 2.0](https://www.polymer-project.org/blog/2017-05-15-time-for-two) 版本.
|
||||
就在前几天的 Google I/O 2017 上, Polymer 正式发布了 [Polymer 2.0](https://www.polymer-project.org/blog/2017-05-15-time-for-two) 版本.
|
||||
|
||||
来看一下 Polymer 2.0 的一些变化:
|
||||
- 使用 Shadow DOM v1 代替 Polymer.dom. Shady DOM从 Polymer 中分离出来。
|
||||
- 使用 Shadow DOM v1 代替 Polymer.dom. Shady DOM 从 Polymer 中分离出来。
|
||||
- 使用 标准的 ES6 类和 Custom Elements v1 来自定义元素.
|
||||
- 还有数据系统的改进和生命周期的变更.
|
||||
|
||||
可以看到, Polymer 的这次升级主要是将 Shadow Dom 和 Custom Elements 升级到 v1 版本, 以获得更多浏览器的原生支持. 下一 代Web Components - v1规范,Chrome 已经支持了,Web Components 规范中的2个主要部分 - [Shadow Dom](https://www.chromestatus.com/feature/4667415417847808) 和 [Custom Elements](https://www.chromestatus.com/feature/4696261944934400). Safari在10版本中, 支持了 [Shadow DOM v1](https://webkit.org/status/#feature-shadow-dom) 规范并且完成了在Webkit内核中对 [Custom Elements v1](https://webkit.org/blog/7027/introducing-custom-elements/) 规范的实现;Firefox对 [Shadow DOM](https://platform-status.mozilla.org/#shadow-dom) 和 [Custom Elements v1规范](https://platform-status.mozilla.org/#custom-elements) 支持正在开发中;Edge也将对 [Shadow DOM](https://developer.microsoft.com/en-us/microsoft-edge/platform/status/shadowdom/) 和 [Custom Elements](https://developer.microsoft.com/en-us/microsoft-edge/platform/status/customelements/) 支持规划到他们的开发roadmap中。
|
||||
可以看到, Polymer 的这次升级主要是将 Shadow Dom 和 Custom Elements 升级到 v1 版本, 以获得更多浏览器的原生支持. 下一 代 Web Components - v1 规范,Chrome 已经支持了,Web Components 规范中的 2 个主要部分 - [Shadow Dom](https://www.chromestatus.com/feature/4667415417847808) 和 [Custom Elements](https://www.chromestatus.com/feature/4696261944934400). Safari 在 10 版本中, 支持了 [Shadow DOM v1](https://webkit.org/status/#feature-shadow-dom) 规范并且完成了在 Webkit 内核中对 [Custom Elements v1](https://webkit.org/blog/7027/introducing-custom-elements/) 规范的实现;Firefox 对 [Shadow DOM](https://platform-status.mozilla.org/#shadow-dom) 和 [Custom Elements v1 规范](https://platform-status.mozilla.org/#custom-elements) 支持正在开发中;Edge 也将对 [Shadow DOM](https://developer.microsoft.com/en-us/microsoft-edge/platform/status/shadowdom/) 和 [Custom Elements](https://developer.microsoft.com/en-us/microsoft-edge/platform/status/customelements/) 支持规划到他们的开发 roadmap 中。
|
||||
|
||||
这段时间, 大家都在讨论 react, vue, angular, 这些框架. 或者 该使用 redux 还 是 mobx 做数据管理. 在这个契机下, 我想我们可以不单单去思考这些框架, 也可以更多地去思考和了解 Web Components 标准. 对于 Web Components标准有一些思考. 所以我选了一篇关于 Web Components 的文章, 想让大家对于 Web Components 的发展, 和 Web Componets 与现在的主流框架如何协作有更多的思考和讨论.
|
||||
这段时间, 大家都在讨论 react, vue, angular, 这些框架. 或者 该使用 redux 还 是 mobx 做数据管理. 在这个契机下, 我想我们可以不单单去思考这些框架, 也可以更多地去思考和了解 Web Components 标准. 对于 Web Components 标准有一些思考. 所以我选了一篇关于 Web Components 的文章, 想让大家对于 Web Components 的发展, 和 Web Componets 与现在的主流框架如何协作有更多的思考和讨论.
|
||||
|
||||
|
||||
# 2 内容概要
|
||||
|
||||
**The broken promise of Web Components**
|
||||
原文作者dmitriid主要是在喷Web Components从2011年到2017年这6年间毫无进展, 一共产出了6份标准, 其中两份已经被弃用. 几乎只有一个主流浏览器(chrome) 支持.
|
||||
原文作者 dmitriid 主要是在喷 Web Components 从 2011 年到 2017 年这 6 年间毫无进展, 一共产出了 6 份标准, 其中两份已经被弃用. 几乎只有一个主流浏览器(chrome) 支持.
|
||||
|
||||

|
||||
|
||||
|
||||
- Web Components 这些规范强依赖 JS 的实现
|
||||
- Custom Elements 是 JS 脚本的一部分
|
||||
- HTML Templates 的出现就是为了被JS 脚本使用
|
||||
- HTML Templates 的出现就是为了被 JS 脚本使用
|
||||
- Shadow Dom 也需要配合 JS 脚本使用
|
||||
- 只有 HTML imports 可以脱离 JS 脚本使用
|
||||
- Web Components 操作 DOM
|
||||
@@ -38,16 +38,16 @@
|
||||
- 为了突破限制使用不同的方法来传递数据
|
||||
- CSS 作用域, 可以见上次精读[《请停止 css-in-js 的行为》](https://github.com/dt-fe/weekly/issues/12)
|
||||
|
||||
**来看一下Polymer 的 核心成员 Rob Dodson 对于本文的回应: Regarding the broken promise of Web Components**
|
||||
**来看一下 Polymer 的 核心成员 Rob Dodson 对于本文的回应: Regarding the broken promise of Web Components**
|
||||
|
||||
- Web Components 特性需要被浏览器支持,必须有平缓的过渡,良好的兼容,以及成熟的方案,因此推进速度会比较慢一些。
|
||||
- React 很棒, 但是也不要忽略其他基于 Web Components 的优秀库比如 [Amp](https://www.ampproject.org/)
|
||||
- 对于 DOM 更新的抽象比如 React/JSX很赞, 但是也带来了一些损耗. 在旧的移动设备上, 加载一个大的js 包性能依旧不理想, 最佳的做法是拆分你的 JS 包, 按需加载.
|
||||
- 使用 JSX 和 虚拟 DOM是很酷, 也可以直接把 JSX 用在 Web Components 内, 像[SkateJS](https://github.com/skatejs/skatejs)库, 已经在做这个事情了.
|
||||
- 没有标准的数据绑定, Polymer的数据绑定, 现在是基于[MDV](https://github.com/toolkitchen/mdv), 很多开发者更倾向于基于 Observables或者 ES6 Proxies的数据绑定方案.
|
||||
- 处理组件的字符串属性是很烦人, 但是由于每一个组件都是一个类的实例, 可以利用ES6 的 getters/setters来改变属性.
|
||||
- 对于 DOM 更新的抽象比如 React/JSX 很赞, 但是也带来了一些损耗. 在旧的移动设备上, 加载一个大的 js 包性能依旧不理想, 最佳的做法是拆分你的 JS 包, 按需加载.
|
||||
- 使用 JSX 和 虚拟 DOM 是很酷, 也可以直接把 JSX 用在 Web Components 内, 像[SkateJS](https://github.com/skatejs/skatejs)库, 已经在做这个事情了.
|
||||
- 没有标准的数据绑定, Polymer 的数据绑定, 现在是基于[MDV](https://github.com/toolkitchen/mdv), 很多开发者更倾向于基于 Observables 或者 ES6 Proxies 的数据绑定方案.
|
||||
- 处理组件的字符串属性是很烦人, 但是由于每一个组件都是一个类的实例, 可以利用 ES6 的 getters/setters 来改变属性.
|
||||
|
||||
Rob Dodson对于 Web Components 依然充满信心, 但是也承认推进标准总会有各种阻碍, 不可能像推荐框架一样快速把事情解决.
|
||||
Rob Dodson 对于 Web Components 依然充满信心, 但是也承认推进标准总会有各种阻碍, 不可能像推荐框架一样快速把事情解决.
|
||||
|
||||
# 3 精读
|
||||
|
||||
@@ -55,11 +55,11 @@ Rob Dodson对于 Web Components 依然充满信心, 但是也承认推进标准
|
||||
[@camsong](https://www.zhihu.com/people/078cc0fb15845759ad8295b0f0e50099) [@黄子毅](https://github.com/ascoders) [@杨森](https://www.zhihu.com/people/c93b7957f6308990c7e3b16103c9356b) [@rccoder](https://github.com/rccoder) [@alcat2008](https://github.com/alcat2008)精读由此归纳。
|
||||
|
||||
### 标准与框架
|
||||
Web Components 作为一个标准,骨子里的进度就会落后于当前可行的技术体系。正如文中所说,浏览器厂商 ship 一个新功能是很严肃的,很可能会影响到一票的线上业务,甚至会影响到一个产业(遥想当年 [Chrome Extension 禁用 NPAPI](https://blog.chromium.org/2013/09/saying-goodbye-to-our-old-friend-npapi.html)时的一片哀鸿遍野,许多返利插件都使用了这种技术)。那么 Web Components的缓慢推进也在情理之中了.
|
||||
即使真的有一天这个标准建立起来,Web Components作为浏览器底层特性不应该拿出来和React这类应用层框架相比较. 未来Web Components会做为浏览器非常重要的特性存在。API偏低层操作,会易用性不够. 在很长时间内开发者依旧会使用 React/Vue/Angular/Polymer 这样的框架,Web Components可能会做为这些框架的底层做一些 浏览器层面上的支持.
|
||||
Web Components 作为一个标准,骨子里的进度就会落后于当前可行的技术体系。正如文中所说,浏览器厂商 ship 一个新功能是很严肃的,很可能会影响到一票的线上业务,甚至会影响到一个产业(遥想当年 [Chrome Extension 禁用 NPAPI](https://blog.chromium.org/2013/09/saying-goodbye-to-our-old-friend-npapi.html)时的一片哀鸿遍野,许多返利插件都使用了这种技术)。那么 Web Components 的缓慢推进也在情理之中了.
|
||||
即使真的有一天这个标准建立起来,Web Components 作为浏览器底层特性不应该拿出来和 React 这类应用层框架相比较. 未来 Web Components 会做为浏览器非常重要的特性存在。API 偏低层操作,会易用性不够. 在很长时间内开发者依旧会使用 React/Vue/Angular/Polymer 这样的框架,Web Components 可能会做为这些框架的底层做一些 浏览器层面上的支持.
|
||||
|
||||
### 不需要 vendor 的自定义组件间调用
|
||||
在 Webpack 大行其道的时代,想在运行时做到组件即引即用变得很困难,因为这些组件大多是通过 React/Vue/Angular 开发的。不得不考虑引入一大堆 Vendor 包,这些 Vendor 里可能还必须包含 React 这类两个版本不能同时使用的库。目前我们团队在做组件化方案时就遇到这个问题,只能想办法避免两个版本的出现。你可以说这是 React 或 Webpack 引入的问题,但并没有看到 Web Compnents 标准化的解决方案。我想未来Web Components可能会作为浏览器的底层, 出现基于底层的标准方案来做组件间的相互应用的方法.
|
||||
在 Webpack 大行其道的时代,想在运行时做到组件即引即用变得很困难,因为这些组件大多是通过 React/Vue/Angular 开发的。不得不考虑引入一大堆 Vendor 包,这些 Vendor 里可能还必须包含 React 这类两个版本不能同时使用的库。目前我们团队在做组件化方案时就遇到这个问题,只能想办法避免两个版本的出现。你可以说这是 React 或 Webpack 引入的问题,但并没有看到 Web Compnents 标准化的解决方案。我想未来 Web Components 可能会作为浏览器的底层, 出现基于底层的标准方案来做组件间的相互应用的方法.
|
||||
|
||||
|
||||
### 为什么对 Web components 讨论不断
|
||||
@@ -69,7 +69,7 @@ Web Components 作为一个标准,骨子里的进度就会落后于当前可
|
||||
但使用前端框架的问题也日益暴露,随着前端框架种类的增多,同一个框架不同版本之间无法共存,导致组件无法跨框架复用,甚至只能固定在框架的某个版本,这与前端未来的模块化发展是相违背的,我们越是与之抗衡,就越希望 Web components 能站出来解决这个问题,因为浏览器原生支持模块化,相当于将 react angular vue 的能力内置在浏览器中,而且一定会向前兼容(这也是 Web components 推进缓慢的原因)。
|
||||
|
||||
# 4 总结
|
||||
我觉得 Web Components作为浏览器底层特性不应该拿出来和React, vue 这类应用层框架相比较. Web Components 的方向以及提供的价值都不会跟 应用框架一致. 而 Web Components 作为未来的 Web 组件标准 , 它在任何生态中都可以运行良好. 我倒是更加期待应用层去基于 Web Components 去做更多的实现, 让组件超越框架存在, 可以在不同技术栈中使用.
|
||||
我觉得 Web Components 作为浏览器底层特性不应该拿出来和 React, vue 这类应用层框架相比较. Web Components 的方向以及提供的价值都不会跟 应用框架一致. 而 Web Components 作为未来的 Web 组件标准 , 它在任何生态中都可以运行良好. 我倒是更加期待应用层去基于 Web Components 去做更多的实现, 让组件超越框架存在, 可以在不同技术栈中使用.
|
||||
|
||||
|
||||
> 讨论地址是:[精读《Web Components 的困境》 · Issue #15 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/15)
|
||||
@@ -62,7 +62,7 @@ Chrome Dev Tools 非常强大,[dev-tips](https://umaar.com/dev-tips/) 列出
|
||||
|
||||
### 移动端控制台
|
||||
|
||||
- [Chrome远程调试](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews) app 支持后,连接 usb 或者局域网,即可通过 Dev Tools 调试 webview 页面。
|
||||
- [Chrome 远程调试](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews) app 支持后,连接 usb 或者局域网,即可通过 Dev Tools 调试 webview 页面。
|
||||
- [Weinre](http://people.apache.org/~pmuellr/weinre/docs/latest/Home.html) 通过页面加载脚本,与 pc 端调试器通信。
|
||||
- 通过内嵌控制台解决,比如 [eruda](http://eruda.liriliri.io/) [VConsole](https://github.com/WechatFE/vConsole)
|
||||
- [Rosin](http://alloyteam.github.io/Rosin/) fiddler 的一个插件,协助移动页面调试。
|
||||
@@ -107,7 +107,7 @@ connect(props => ({
|
||||
|
||||
## HOC 的具体实践
|
||||
|
||||
HOC 在真实场景下的运行非常多,之前笔者在 [基于Decorator的组件扩展实践](https://zhuanlan.zhihu.com/p/22054582) 一文中也提过使用高阶组件将更细粒度的组件组合成 Selector 与 Search。结合精读文章,这次让我们通过 Form 组件的抽象来表现 HOC 具有的良好扩展机制。
|
||||
HOC 在真实场景下的运行非常多,之前笔者在 [基于 Decorator 的组件扩展实践](https://zhuanlan.zhihu.com/p/22054582) 一文中也提过使用高阶组件将更细粒度的组件组合成 Selector 与 Search。结合精读文章,这次让我们通过 Form 组件的抽象来表现 HOC 具有的良好扩展机制。
|
||||
|
||||
Form 中会包含各种不同的组件,常见的有 Input、Selector、Checkbox 等等,也会有根据业务需求加入的自定义组件。Form 灵活多变,从功能上看,表单校验可能为单组件值校验,也可能为全表单值校验,可能为常规检验,比如:非空、输入限制,也可能需要与服务端配合,甚至需要根据业务特点进行定制。从 UI 上看,检验结果显示的位置,可能在组件下方,也可能是在组件右侧。
|
||||
|
||||
@@ -115,7 +115,7 @@ Form 中会包含各种不同的组件,常见的有 Input、Selector、Checkbo
|
||||
|
||||

|
||||
|
||||
至于 HOC 在 Form 上的具体实现,首先将表单中的组件(Input、Selector...)与相应 validator 与组件值回调函数名(trigger)传入 Decorator,将 validator 与 trigger 相绑定。Decorator 完成了各种不同组件与 Form 内置 Store 间 value 的传递、校验功能的抽象,即精读文章中提到 Props Proxy 方式的其中两种作用:**提取state** 与 **操作props**
|
||||
至于 HOC 在 Form 上的具体实现,首先将表单中的组件(Input、Selector...)与相应 validator 与组件值回调函数名(trigger)传入 Decorator,将 validator 与 trigger 相绑定。Decorator 完成了各种不同组件与 Form 内置 Store 间 value 的传递、校验功能的抽象,即精读文章中提到 Props Proxy 方式的其中两种作用:**提取 state** 与 **操作 props**
|
||||
|
||||
```javascript
|
||||
function formFactoryFactory({
|
||||
@@ -215,7 +215,7 @@ var bar = foo.bind(obj)
|
||||
bar()
|
||||
```
|
||||
|
||||
### 3.2.2 es6绑定
|
||||
### 3.2.2 es6 绑定
|
||||
|
||||
这种情况类似使用箭头函数创建成员变量,以下方式等于创建了没有挂载到原型链的匿名函数,因此 this 不会丢失。
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
# 1 引言
|
||||
|
||||
随着前端ES6 ES7 的一路前行, 我们大前端借鉴和引进了各种其他编程语言中的概念、特性、模式;
|
||||
我们可以使用函数式Functional编程设计,可以使用面向对象OOP的设计,可以使用面向接口的思想,也可以使用AOP,
|
||||
随着前端 ES6 ES7 的一路前行, 我们大前端借鉴和引进了各种其他编程语言中的概念、特性、模式;
|
||||
我们可以使用函数式 Functional 编程设计,可以使用面向对象 OOP 的设计,可以使用面向接口的思想,也可以使用 AOP,
|
||||
可以使用注解,代理、反射,各种设计模式; 在大前端辉煌发展、在数据时代的当下 我们一起阅读了一篇设计相关的老文:
|
||||
《The DCI Architecture》
|
||||
一起来再探索和复习一下 相关的设计和思想
|
||||
@@ -11,15 +11,15 @@
|
||||
|
||||
# 2 内容摘要
|
||||
|
||||
DCI是数据Data 场景Context 交互Interactions 简称, 重点是关注 数据的不同场景的交互行为, 是面向对象系统 状态和行为的一种范式设计;
|
||||
DCI在许多方面是许多过去范式的统一,多年来这些模式已经成为面向对象编程的辅助工具。
|
||||
DCI 是数据 Data 场景 Context 交互 Interactions 简称, 重点是关注 数据的不同场景的交互行为, 是面向对象系统 状态和行为的一种范式设计;
|
||||
DCI 在许多方面是许多过去范式的统一,多年来这些模式已经成为面向对象编程的辅助工具。
|
||||
|
||||
尽管面向切面的编程(AOP)也有其他用途,但DCI满足了许多AOP的应用以及Aspects在解决问题方面的许多目标。根据AOP的基本原理,DCI基于深层次的反射或元编程。
|
||||
与Aspects不同,角色聚合并组合得很好。Context提供角色集之间的关联的范围关闭,而Aspect仅与应用它们的对象配对。
|
||||
在许多时候,虽然混合本身缺乏我们在Context语义中发现的动力 ,但DCI反映了混合风格策略。
|
||||
DCI实现了多范式设计的许多简单目标,能够将过程逻辑与对象逻辑分开。然而,DCI具有比多范式设计提供的更强大的技术更好的耦合和内聚效果
|
||||
尽管面向切面的编程(AOP)也有其他用途,但 DCI 满足了许多 AOP 的应用以及 Aspects 在解决问题方面的许多目标。根据 AOP 的基本原理,DCI 基于深层次的反射或元编程。
|
||||
与 Aspects 不同,角色聚合并组合得很好。Context 提供角色集之间的关联的范围关闭,而 Aspect 仅与应用它们的对象配对。
|
||||
在许多时候,虽然混合本身缺乏我们在 Context 语义中发现的动力 ,但 DCI 反映了混合风格策略。
|
||||
DCI 实现了多范式设计的许多简单目标,能够将过程逻辑与对象逻辑分开。然而,DCI 具有比多范式设计提供的更强大的技术更好的耦合和内聚效果
|
||||
|
||||
结合ATM 汇款场景案例,讲解了一下 DCI
|
||||
结合 ATM 汇款场景案例,讲解了一下 DCI
|
||||
角色提供了和用户相关 自然的边界,以转账为例,我们实际谈论的是钱的转移,以及源账户和目标账户的角色,算法(用例 角色行为集合)应该是这样:
|
||||
1.账户拥有人选择从一个账户到另外一个账户的钞票转移。
|
||||
2.系统显示有效账户
|
||||
@@ -35,12 +35,12 @@ DCI实现了多范式设计的许多简单目标,能够将过程逻辑与对
|
||||
2.源账户确认余额可用
|
||||
3.源账户减少其帐目
|
||||
4.源账户请求目标账户增加其帐目
|
||||
5.源账户请求目标账户更新其日志log
|
||||
5.源账户请求目标账户更新其日志 log
|
||||
6.源账户结束交易事务
|
||||
7.源账户显示给账户拥有人转账成功。
|
||||
|
||||
|
||||
```
|
||||
```plain
|
||||
template <class ConcreteAccountType>
|
||||
class TransferMoneySourceAccount: public MoneySource
|
||||
{
|
||||
@@ -88,7 +88,7 @@ DCI 尝试从人类思维角度出发,举一个例子:为什么在看电影
|
||||
2. 人或物发生了什么行为、交互?
|
||||
3. 现在在哪?厨房?太空舱?或者原始森林?
|
||||
|
||||
很快把这三件事弄清楚,我们就能快速理解当前场景的逻辑,并且**轻松理解该场景继续发生的状况**,即便是盗梦空间这种烧脑的电影,当我们搞清楚这三个问题后,就算街道发生了180度扭曲,也不会存在理解障碍,反而可以吃着爆米花享受,直到切换到下一个场景为止。
|
||||
很快把这三件事弄清楚,我们就能快速理解当前场景的逻辑,并且**轻松理解该场景继续发生的状况**,即便是盗梦空间这种烧脑的电影,当我们搞清楚这三个问题后,就算街道发生了 180 度扭曲,也不会存在理解障碍,反而可以吃着爆米花享受,直到切换到下一个场景为止。
|
||||
|
||||
当我们把街道扭曲 180 度的能力放在街道对象上时,理解就变的复杂了:这个函数什么时候被调用?为什么不好好承载车辆而自己发生扭曲?这就像电影开始时,把电影里播放的所有关于街道的状态都走马灯过一遍:我们看到街道通过了车辆、又卷曲、又发生了爆炸,实在觉得莫名其妙。
|
||||
|
||||
@@ -210,23 +210,23 @@ object MoneyTransferApp extends App {
|
||||
|
||||
- [Comparison of Architecture presentation patterns MVP(SC),MVP(PV),PM,MVVM and MVC](https://www.codeproject.com/Articles/66585/Comparison-of-Architecture-presentation-patterns-M)
|
||||
- [The DCI Architecture: A New Vision of Object-Oriented Programming](http://www.artima.com/articles/dci_vision.html)
|
||||
- [干净的架构The Clean Architecture](https://www.bbsmax.com/A/pRdBWY3ezn/)
|
||||
- [MVC的替代方案](https://gxnotes.com/article/71237.html)
|
||||
- [展示模式架构比较MVP(SC),MVP(PV),PM,MVVM和MVC](http://blog.csdn.net/lihenair/article/details/51791915)
|
||||
- [干净的架构 The Clean Architecture](https://www.bbsmax.com/A/pRdBWY3ezn/)
|
||||
- [MVC 的替代方案](https://gxnotes.com/article/71237.html)
|
||||
- [展示模式架构比较 MVP(SC),MVP(PV),PM,MVVM 和 MVC](http://blog.csdn.net/lihenair/article/details/51791915)
|
||||
- [Software Architecture Design](https://github.com/zenany/weekly/blob/master/resources/software_architecture.md)
|
||||
- [【译】什么是 Flux 架构?(兼谈 DDD 和 CQRS)](https://blog.jimmylv.info/2016-07-07-what-the-flux-on-flux-ddd-and-cqrs/)
|
||||
|
||||
|
||||
## 结合DCI 设想开发的过程中使用到一些设计方法和原则
|
||||
## 结合 DCI 设想开发的过程中使用到一些设计方法和原则
|
||||
|
||||
我们在开发的过程中多多少少都会使用到一些设计方法和原则
|
||||
DCI 重点是关注 数据的不同场景的交互行为, 是面向对象系统 状态和行为的一种范式设计;
|
||||
|
||||
它能够将过程逻辑与对象逻辑分开,是一种典型的行为模式设计;
|
||||
很好的点是 它根据AOP的基本原理,DCI 提出基于AOP 深层次的元编程(可以理解成面向接口编程), 去促使系统的内聚效果和降低耦合度;
|
||||
很好的点是 它根据 AOP 的基本原理,DCI 提出基于 AOP 深层次的元编程(可以理解成面向接口编程), 去促使系统的内聚效果和降低耦合度;
|
||||
|
||||
举个例子:
|
||||
在一个BI系统中, 在业务的发展中, 这个系统使用到了多套的 底层图表库,比如: Echarts, G2,Recharts, FusionChart; 等等;
|
||||
在一个 BI 系统中, 在业务的发展中, 这个系统使用到了多套的 底层图表库,比如: Echarts, G2,Recharts, FusionChart; 等等;
|
||||
|
||||
那么问题来了,
|
||||
1. 如何去同时支持 这些底层库, 并且达到很容易切换的一个效果?
|
||||
@@ -234,19 +234,19 @@ DCI 重点是关注 数据的不同场景的交互行为, 是面向对象系
|
||||
3. 如何去考虑扩展业务 对图表的日益增强的业务功能(如: 行列转换、智能格式化 等等)
|
||||
|
||||
带着这些问题, 我们再来看下 DCI 给我们的启示, 我们来试试看相应的解法:
|
||||
1. 图表的模型数据就是 数据Data , 我们可以把[日益增强的业务功能] 认为是各个场景交互Interactions;
|
||||
1. 图表的模型数据就是 数据 Data , 我们可以把[日益增强的业务功能] 认为是各个场景交互 Interactions;
|
||||
2. 接入更多类型的图表咋么搞?
|
||||
不同类型的图表其实是图表数据模型的转换,我们也可以把这些转换的行为过程作为一个个的切片(Aspect),每个切片都是独立的, 松耦合的 ;
|
||||

|
||||
|
||||
3. 接入多套底层库怎么搞? 每个图形库的 build方法,render 方法 , resize 方法,repaint 方法 都不一样 ,怎么搞 ? 我们可以使用 DCI 提到的元编程- 我们在这里理解为面向接口编程, 我们分装一层 统一的接口;
|
||||
3. 接入多套底层库怎么搞? 每个图形库的 build 方法,render 方法 , resize 方法,repaint 方法 都不一样 ,怎么搞 ? 我们可以使用 DCI 提到的元编程- 我们在这里理解为面向接口编程, 我们分装一层 统一的接口;
|
||||
利用面向接口的父类引用指向子类对象 我们就可以很方便的 接入更多的 implement 接入更多的图形库(当然,一个系统统一一套是最好的);
|
||||
|
||||
|
||||
|
||||
# 4 总结
|
||||
|
||||
DCI是数据Data 场景Context 交互Interactions的简称,DCI是一种特别关注行为的设计模式(行为模式),
|
||||
DCI 是数据 Data 场景 Context 交互 Interactions 的简称,DCI 是一种特别关注行为的设计模式(行为模式),
|
||||
DCI 关注数据不同场景的交互行为, 是面向对象 状态和行为的一种范式设计;DCI 尝试从人类思维,过程化设计一些行为;
|
||||
DCI 也会使用一些面向切面和接口编程的设计思想去达到高内聚低耦合的目标。
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
# 2 内容概要
|
||||
|
||||
### TC39是什么?包括哪些人?
|
||||
### TC39 是什么?包括哪些人?
|
||||
|
||||
一个推动 JavaScript 发展的委员会,由各个主流浏览器厂商的代表构成。
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
### TC39 这群人主要的工作是什么?
|
||||
|
||||
制定ECMAScript标准,标准生成的流程,并实现。
|
||||
制定 ECMAScript 标准,标准生成的流程,并实现。
|
||||
|
||||
### 标准的流程是什么样的?
|
||||
|
||||
@@ -26,34 +26,34 @@
|
||||
|
||||
- stage0 `strawman`
|
||||
|
||||
任何讨论、想法、改变或者还没加到提案的特性都在这个阶段。只有TC39成员可以提交。
|
||||
任何讨论、想法、改变或者还没加到提案的特性都在这个阶段。只有 TC39 成员可以提交。
|
||||
|
||||
- stage1 `proposal`
|
||||
(1)产出一个正式的提案。
|
||||
(2)发现潜在的问题,例如与其他特性的关系,实现难题。
|
||||
(3)提案包括详细的API描述,使用例子,以及关于相关的语义和算法。
|
||||
(3)提案包括详细的 API 描述,使用例子,以及关于相关的语义和算法。
|
||||
|
||||
- stage2 `draft`
|
||||
(1)提供一个初始的草案规范,与最终标准中包含的特性不会有太大差别。草案之后,原则上只接受增量修改。
|
||||
(2)开始实验如何实现,实现形式包括polyfill, 实现引擎(提供草案执行本地支持),或者编译转换(例如babel)
|
||||
(2)开始实验如何实现,实现形式包括 polyfill, 实现引擎(提供草案执行本地支持),或者编译转换(例如 babel)
|
||||
|
||||
- stage3 `candidate`
|
||||
(1)候选阶段,获得具体实现和用户的反馈。此后,只有在实现和使用过程中出现了重大问题才会修改。
|
||||
(1)规范文档必须是完整的,评审人和ECMAScript的编辑要在规范上签字。
|
||||
(2)至少要在一个浏览器中实现,提供polyfill或者babel插件。
|
||||
(1)规范文档必须是完整的,评审人和 ECMAScript 的编辑要在规范上签字。
|
||||
(2)至少要在一个浏览器中实现,提供 polyfill 或者 babel 插件。
|
||||
|
||||
- stage4 `finished`
|
||||
(1)已经准备就绪,该特性会出现在下个版本的ECMAScript规范之中。。
|
||||
(2)需要通过有2个独立的实现并通过验收测试,以获取使用过程中的重要实践经验。
|
||||
(1)已经准备就绪,该特性会出现在下个版本的 ECMAScript 规范之中。。
|
||||
(2)需要通过有 2 个独立的实现并通过验收测试,以获取使用过程中的重要实践经验。
|
||||
|
||||
### 一般可以去哪里查看TC39标准的进程呢?
|
||||
### 一般可以去哪里查看 TC39 标准的进程呢?
|
||||
|
||||
stage0 的提案 https://github.com/tc39/proposals/blob/master/stage-0-proposals.md
|
||||
stage1 - 4 的提案 https://github.com/tc39/proposals
|
||||
|
||||
### 我们怎么在程序中应用这些新特性呢?
|
||||
|
||||
babel的插件:`babel-presets-stage-0` `babel-presets-stage-1` `babel-presets-stage-2` `babel-presets-stage-3` `babel-presets-stage-4`
|
||||
babel 的插件:`babel-presets-stage-0` `babel-presets-stage-1` `babel-presets-stage-2` `babel-presets-stage-3` `babel-presets-stage-4`
|
||||
|
||||
# 3 精读
|
||||
|
||||
@@ -617,7 +617,7 @@ const firstName = message.body?.user?.firstName || 'default'
|
||||
|
||||
```javascript
|
||||
const firstName =
|
||||
()message &&
|
||||
(message &&
|
||||
message.body &&
|
||||
message.body.user &&
|
||||
message.body.user.firstName) || 'default'
|
||||
@@ -627,7 +627,7 @@ const firstName =
|
||||
|
||||
### [Math.signbit: IEEE-754 sign bit](http://jfbastien.github.io/papers/Math.signbit.html)
|
||||
|
||||
当值为 负数 或 -0 时返回 `true`。由于 `Math.sign` 不区分 +0 与 -0,因此提案建议增加此函数,而且此函数在 c、c++、go语言都有实现。
|
||||
当值为 负数 或 -0 时返回 `true`。由于 `Math.sign` 不区分 +0 与 -0,因此提案建议增加此函数,而且此函数在 c、c++、go 语言都有实现。
|
||||
|
||||
### [Error stacks](https://github.com/tc39/proposal-error-stacks)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 1. 摘要
|
||||
|
||||
日期选择器作为基础组件重要不可或缺的一员,大家已经快习惯它一成不变的样子,输入框+日期选择弹出层。但到业务中,这种墨守成规的样子真的能百分百契合业务需求吗。这篇文章从多个网站的日期选择场景出发,企图归纳出日期选择器的最佳实践。这篇文章对移动端的日期选择暂无涉猎,都是PC端,列举出通用场景,每个类型日期选择器需要考虑的设计。
|
||||
日期选择器作为基础组件重要不可或缺的一员,大家已经快习惯它一成不变的样子,输入框+日期选择弹出层。但到业务中,这种墨守成规的样子真的能百分百契合业务需求吗。这篇文章从多个网站的日期选择场景出发,企图归纳出日期选择器的最佳实践。这篇文章对移动端的日期选择暂无涉猎,都是 PC 端,列举出通用场景,每个类型日期选择器需要考虑的设计。
|
||||
文章链接:Designing The Perfect Date And Time Picker
|
||||
感谢本期评论官 @黄子毅 @流形 @王亮 @赵阳 @不知名的花瓣工程师
|
||||
# 2. 设计原则
|
||||
@@ -21,9 +21,9 @@
|
||||
|
||||
2)用户自定义输入如何保证日期格式正确性?
|
||||
|
||||
3)是否需要提供预设场景输入? 比如昨天,三天前,七天前,30天前?像很多数据分析场景,分析师会关注数据周期,比如流量的周环比,月环比,年环比。
|
||||
3)是否需要提供预设场景输入? 比如昨天,三天前,七天前,30 天前?像很多数据分析场景,分析师会关注数据周期,比如流量的周环比,月环比,年环比。
|
||||
|
||||
4)是否需要包含默认值?如果有默认,应该是什么?像google flight 根据用户历史数据提供默认值,临近节假日默认填充节假日。同时像有些数据场景,数据存在延迟,需要默认提供T-1/T-2 ,避免用户选择当天。
|
||||
4)是否需要包含默认值?如果有默认,应该是什么?像 google flight 根据用户历史数据提供默认值,临近节假日默认填充节假日。同时像有些数据场景,数据存在延迟,需要默认提供 T-1/T-2 ,避免用户选择当天。
|
||||
|
||||
5)当用户激活输入框时,是否保留默认值?
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
2)用户选中后是否立刻做背景色提示?
|
||||
|
||||
3)当用户选择时,区间是否需要随着用户动作改变?比如用户hover时,动态改变选中区间。
|
||||
3)当用户选择时,区间是否需要随着用户动作改变?比如用户 hover 时,动态改变选中区间。
|
||||
|
||||
4)是否提供快捷键切换 日、月、年选择?
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||

|
||||
|
||||
采用与用户交互的方式选择日期,如果今后应用上AI,单纯的日期选择器是不是会消失不见呢?..
|
||||
采用与用户交互的方式选择日期,如果今后应用上 AI,单纯的日期选择器是不是会消失不见呢?..
|
||||
## 3.5 特殊标识周末
|
||||

|
||||
在机票、旅行场景中,周末是大家最有可能出行的时间点,采用竖线划分的方式着重标注提醒。
|
||||
@@ -106,6 +106,6 @@
|
||||
|
||||

|
||||
|
||||
总得来说,日期选择器是一个业务组件,虽然现有很多组件库把它纳入UI基础组件。但在每个不通的业务场景和需求下的展现形式、交互都会有所有不同。首先一定一定要明确确定需要日期选择器的场景,尤其是与日期强关联的业务,比如机票定价、日程安排,结合到日期选择器中更直观,提高用户对信息的检索效率。满足用户需求场景的同时,尽量减少用户操作链路。
|
||||
总得来说,日期选择器是一个业务组件,虽然现有很多组件库把它纳入 UI 基础组件。但在每个不通的业务场景和需求下的展现形式、交互都会有所有不同。首先一定一定要明确确定需要日期选择器的场景,尤其是与日期强关联的业务,比如机票定价、日程安排,结合到日期选择器中更直观,提高用户对信息的检索效率。满足用户需求场景的同时,尽量减少用户操作链路。
|
||||
|
||||
看到最后点个赞呗,给你比小心心 ❤ ~~
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
正如上面所说,我推荐以开放性问题开场,这样便于了解候选人的经历、熟悉哪些技术点,便于后面的技术提问。如果开场就以准备好的题目展开车轮战,容易引起候选人心里紧张,同时我们问的问题不一定是候选人所在行的,技术问题不是每一个都那么重要,很多时候我们只看到了候选人的冰山一角,但此时气氛已经尴尬,很多时候会遗漏优秀人才。
|
||||
|
||||
开放性问题最好基于行为面试法询问(Star法则):
|
||||
开放性问题最好基于行为面试法询问(Star 法则):
|
||||
|
||||
- Situation: 场景 - 当时是怎样的场景
|
||||
- Task: 任务 - 当时的任务是什么
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
面试主要是看候选人基础有多扎实,和思维能力。基础主要指的是,候选人提前了解了多少前端相关知识,比如对闭包的理解,对原生 api 的理解?如果候选人没接触过这两个知识点,会有两种情况:
|
||||
|
||||
- **这些知识点看完需要多久?如果是闭包和原生api的定义与用法,候选人这方面的缺陷可以通过5分钟来弥补,那么这种问题到底想考什么?我们真的在乎这5分钟看文档的时间吗?此时应该了解候选人对知识点的感悟,或者学习方式,因为这两点的差距可能几年都无法弥补**
|
||||
- **这些知识点看完需要多久?如果是闭包和原生 api 的定义与用法,候选人这方面的缺陷可以通过 5 分钟来弥补,那么这种问题到底想考什么?我们真的在乎这 5 分钟看文档的时间吗?此时应该了解候选人对知识点的感悟,或者学习方式,因为这两点的差距可能几年都无法弥补**
|
||||
- **如果候选人学习能力非常强,但几乎所有前端知识点都不了解,弥补完大概一共要花 1000*5 分钟,这时候量变引发质变了,是不是说明候选人本身对技术的热情存在问题?**
|
||||
|
||||
通过了基础问题还远远不够。甚至当问一个复杂的问题的时候,如果候选人瞬间把答案完美流畅表达出来,说明这个问题基本上白问了。
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
最后考察候选人的发展潜力与工作态度,我们一般通过询问简单的算法问题,进一步了解候选人是否对技术真正感兴趣,而不只是对前端工程感兴趣。同时,算法问题也考察候选人解决抽象问题的能力,或者让候选人设计一个组件,通过对组件需求的不断升级,考察候选人是否能及时给出解决方案。
|
||||
|
||||
最后时工作态度,首先会考察人品,对不懂的知识点装懂是违背诚信的行为,任何团队都不会要的。同时,**不正视自己技术存在的盲点,将是技术发展的最大阻碍**。不过这里也不怕被候选人套路,如果全部都回答不懂那也不用考虑了。
|
||||
最后是工作态度,首先会考察人品,对不懂的知识点装懂是违背诚信的行为,任何团队都不会要的。同时,**不正视自己技术存在的盲点,将是技术发展的最大阻碍**。不过这里也不怕被候选人套路,如果全部都回答不懂那也不用考虑了。
|
||||
|
||||
# 3 总结
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# 精读《Web fonts: when you need them, when you don’t》
|
||||
本期精读让我们来聊一聊 Web Fonts,文章地址:[https://hackernoon.com/web-fonts-when-you-need-them-when-you-dont-a3b4b39fe0ae](https://hackernoon.com/web-fonts-when-you-need-them-when-you-dont-a3b4b39fe0ae)
|
||||
|
||||
## 文章简介
|
||||
文章分析了 Web Fonts 的优劣具体使用场景。
|
||||
|
||||
## 主要观点
|
||||
- 作者用一张流程图非常言简意赅地概括了文章的上半部分。
|
||||

|
||||
- 当然上半部分作者也讲了很多案例,其中一个很明显的案例就是维基百科利用字体来提升阅读体验,通过文章内的对比,能直观感受到这一点
|
||||
- 文章后半部分着力介绍了怎么解决 Web Font 的带来的弊端:认识 FOUT 带来的问题,如何使用现有的前端解决方案来尽可能避免这个问题,以及样式上优雅降级的几个方案。
|
||||
|
||||
## 把文章带入自己的开发环境
|
||||
作为一个中文开发者,在我们的开发技术栈中,Web Fonts 绝对是属于使用频率比较低的那一类的。本次精读选择这篇文章,也正是一探这一个不常见的领域。
|
||||
|
||||
对于英文字母,26 个字母可以解决大部分的问题,算上大小写和基本符号,一张 ASCII 码标就可以包含住。让我再扩展一下,到大部分的西文书写系统,几百个字符就能解决多语言显示的问题了。但是对于汉语而言,Web Fonts 真的是,想说爱你不容易,因为常用的汉字就有几千个(你想象中国还有《千字文》这种儿童读物……)。字体这东西跟字符数量直接挂钩,是很难通过压缩来获得性能提升的。
|
||||
|
||||
通常的想法就是用多少,取多少,但是这个方法也就只能适用于标题美化等场景。对于一个系统性的前端工程,我们不可能去实现一个动态字符的字体文件(就是统计这个页面上会产生多少个字符,为这个字符集去生成一个字符子集)
|
||||
|
||||
虽然汉字书写系统和西文书写系统天生存在差异,但是把作者在文章中提出来的几个问题再站在中文的角度上再来看一下,也可以得到一个比较客观的答案。以下是我作为一个普通开发者的自问自答:
|
||||
|
||||
1. **字体对你的品牌很关键吗?**(需要特性字体的中文 LOGO 基本都用 PNG 和 SVG 解决了,Web Font 不实用。)
|
||||
2. **字体让你的文字阅读起来更容易了吗?**(我平时开发产品没有成片聚集的文字,用无衬线字体就能满足需求。Web Font 很好,我选择“微软雅黑”。)(注:泛指那些好用的支持全字集的系统自带字体;成片的文字适用衬线字体,个人认为中文的衬线字体,不同的字体带来的阅读体验还是有明显差别的。)
|
||||
3. **你需要在不同设备上显示一样的字体吗?**(好像还没这么苛求吧……微软雅黑好看,安卓上的 Roboto 也很不错啊,Roboto 这种字体还针对移动设备有优化,何乐而不为。)
|
||||
4. **用了 Web Font 你会更开心吗?**(在 icon 中使用 iconfont 让我们告别了 PNG Sprite 图,嗯这很开心。至于文字上用 Web Font,有好用的系统字体你不用,你这是何苦呢)(作者也说了,可能折腾半天还没系统字体看着舒服,那就是一行 font-family 的事情)
|
||||
|
||||
不同产品有着不同的场景,多像文章里问问自己会有最合适的答案。
|
||||
|
||||
## 关于 FOUT 和 FOIT
|
||||
文章中大篇幅地在安利你使用 Web Font,但是也很直白地指出了 Web Font 最大的问题,就是这个 FOUT——Flash Of Unstyled Text。连作者毫不避讳地说了句:“噢我的老天,这太丑了!”
|
||||
|
||||
具体表现是采用了 Web Font 的文案会存在闪动,这个的根本原因在于相比于系统字体,Web Font 最大的弊端在于它是异步加载的,你没有办法避免下载它所用的时间。文章中举了一个例子,在一个图文为主的页面中,一个 542KB 的字体文件,在第 9 秒才加载完成。在那之前只能以系统字体来展示,而在第 9 秒加载完成的时候,还会出现替换字体的情况,文字会突然跳动。
|
||||
|
||||
比 FOUT 更为极端的情况的是 FOIT——Flash Of Invisible Text。很多浏览器的行为,并不是默认展示系统字体,而是直接隐藏。那么即使在极快的网速下也很难避免存在一个几百毫秒的时间滞后。
|
||||
|
||||
不过好在,有一个 font-display 的属性,可以在声明@font-face 的时候配合使用。对于未加载 Web Fonts 的时候,auto 属性可以选择隐藏也就是会产生 FOIT,swap 会产生替换也就是会产生 FOUT,还有 fallback 和 optional 可以控制先 FOIT 后 FOUT 来达到折中方案。
|
||||
|
||||
还有一个思路,那就是预加载,对于字体,浏览器还是能够有效缓存的,如果能够做好预加载,还是不会太影响用户体验的。文章中就提到了一个方案,调用 link 的 rel=preload 来做预加载。因为通常加载字体是在 CSS 中的@font-face 被读到的时候才去加载的,那么就会出现先加载 CSS,后加载字体的情况。如果利用 link 预加载,那么在 CSS 中的@font-face 被读到前就已经开始加载了,那么字体加载和 CSS 加载就可以同时加载,提升速度。
|
||||
|
||||
当然 JS 是万能的,也有一些库在支持这方面功能,例如 bramstein/fontfaceobserver 这样的。
|
||||
|
||||
愚以为,FO*T 这种情况既然无法避免还是要具体情况具体分析的。如果你的用户网速够快,那么隐藏文字会更好,用户无感知;如果网速不确定,而且是文章为主的内容,那么内容至上就应该先用替代字体显示;如果你正在将 Web Font 应用在图标等东西上,那么我们自然不愿意看到满屏的方框方框,这种时候就选择隐藏吧。
|
||||
|
||||
文章也提了一点,如果你的字体授权很贵,但用户端深受 FO*T 折磨,那你还费这钱干嘛。
|
||||
|
||||
## 结论
|
||||
如果能解决 FO*T 的副作用,Web Font 怎么舒服怎么用。但是中文字体大,常用西文字体诸如 Google 字体库又时常被墙,对于中国开发者,Web Font 想说爱你不容易。(还是乖乖用微软雅黑吧,逃……
|
||||
|
||||
## 彩蛋
|
||||
文章里有一段很精彩的话,摘抄出来翻译一下:
|
||||
|
||||
> 如果这个世界上有这样一个 Sketch 或者 Photoshop 的插件,可以在你每次打开一个文件的时候,延迟十秒才显示出字体;那么世界上就没有那么多多余的字体了。
|
||||
>
|
||||
> (译者注:删光设计师的电脑里的奇怪字体也能达到相同目的,哈哈哈~)
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<img src="assets/22/v8.png" width="500" alt="logo" />
|
||||
|
||||
定时刷新一下对 js 的三观,防止经验变成坑。(对IE等浏览器的三观需保持不变)
|
||||
定时刷新一下对 js 的三观,防止经验变成坑。(对 IE 等浏览器的三观需保持不变)
|
||||
|
||||
# 2 内容概要
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
本期精读的文章是:[API设计原则](https://coolshell.cn/articles/18024.html)
|
||||
本期精读的文章是:[API 设计原则](https://coolshell.cn/articles/18024.html)
|
||||
|
||||
# 1 引言
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
由于本文已经是翻译后的文章,概要只列出不涉及 c++ 概念的思路框架,细节请移步[译文](https://coolshell.cn/articles/18024.html)。
|
||||
|
||||
## 好 API 的6个特质
|
||||
## 好 API 的 6 个特质
|
||||
|
||||
极简且完备、语义清晰简单、符合直觉、易于记忆和引导API使用者写出可读代码。
|
||||
极简且完备、语义清晰简单、符合直觉、易于记忆和引导 API 使用者写出可读代码。
|
||||
|
||||
## 静态多态
|
||||
|
||||
@@ -76,7 +76,7 @@ function (const num) {
|
||||
|
||||
## 统一关键字库
|
||||
|
||||
所有api定义之前,先抽离业务和功能语义的关键字,统一关键字库; 可以更好的让多人协作看起来如出一辙, 而且关键字库 更能够让调用者感觉到 符合直觉、语义清晰; 关键字库也是项目组新同学 PREDO 的内容之一, 很有带入感;
|
||||
所有 api 定义之前,先抽离业务和功能语义的关键字,统一关键字库; 可以更好的让多人协作看起来如出一辙, 而且关键字库 更能够让调用者感觉到 符合直觉、语义清晰; 关键字库也是项目组新同学 PREDO 的内容之一, 很有带入感;
|
||||
|
||||
## 单一职责
|
||||
|
||||
@@ -119,6 +119,6 @@ const { setVisible } = this.props.store.article
|
||||
|
||||
最后,如果有精力,最好每半年重构一次(然后完整跑一遍测试)!
|
||||
|
||||
> 讨论地址是:[精读《API设计原则》 · Issue #34 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/34)
|
||||
> 讨论地址是:[精读《API 设计原则》 · Issue #34 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/34)
|
||||
|
||||
> 如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
我为什么要选这篇文章呢?
|
||||
|
||||
之所以选这篇文章, 是因为非常认同作者写这两篇文章的原因. 作者在文中说, 现代JavaScript 的很多概念和思想在快速被传播和扩展, 很多新概念出现在前端相关的博客和文档中, 这些概念对于很多前端开发人员来说, 仍然很陌生. 因此我们有必要来学习一下现代的这些 JavaScript的概念, 看这些概念在现在 JavaScript 的库或应用中是怎么被使用的.
|
||||
之所以选这篇文章, 是因为非常认同作者写这两篇文章的原因. 作者在文中说, 现代 JavaScript 的很多概念和思想在快速被传播和扩展, 很多新概念出现在前端相关的博客和文档中, 这些概念对于很多前端开发人员来说, 仍然很陌生. 因此我们有必要来学习一下现代的这些 JavaScript 的概念, 看这些概念在现在 JavaScript 的库或应用中是怎么被使用的.
|
||||
|
||||
# 2 内容概要
|
||||
|
||||
文章讲了很多现代JavaScript中的概念, 罗列如下:
|
||||
文章讲了很多现代 JavaScript 中的概念, 罗列如下:
|
||||
|
||||
## 纯函数和副作用
|
||||
在了解纯函数之前, 首先要了解副作用. 副作用是指改变了其作用域外的状态. 副作用的举例有调用了一个 API, 操作了一个 DOM节点, 弹出了一个弹窗, 或者改变了一条数据等.
|
||||
在了解纯函数之前, 首先要了解副作用. 副作用是指改变了其作用域外的状态. 副作用的举例有调用了一个 API, 操作了一个 DOM 节点, 弹出了一个弹窗, 或者改变了一条数据等.
|
||||
|
||||
而纯函数则是指 函数的返回值仅仅由参数决定, 当给同样的参数时, 返回值是固定的.
|
||||
|
||||
@@ -27,7 +27,7 @@ Stateless 无状态, 有点像纯函数, 不管理自己的数据或状态, 结
|
||||
|
||||
可变对象与不可变对象概念很清楚, 可变对象指的是在创建后值仍可以被改变, 不可变对象指的是创建后值无法被改变.
|
||||
|
||||
相比于其他语言, 可变对象与不可变对象在 JavaScript 中更加模糊, 当你了解函数式编程时, 你会听到很多不可变对象的好处. 在 JavaScript 中, 你可以通过Object.freeze(obj), 让一个对象变得不可变, 但是注意这是浅层的冻结对象, 如果有一个属性的值是个对象, 那这个对象中的属性是可以被修改的. 现在 JavaScript 也出现了 npm deep-freeze , Immutable.js 这些库来帮助你在 JavaScript 中实现不可变对象.
|
||||
相比于其他语言, 可变对象与不可变对象在 JavaScript 中更加模糊, 当你了解函数式编程时, 你会听到很多不可变对象的好处. 在 JavaScript 中, 你可以通过 Object.freeze(obj), 让一个对象变得不可变, 但是注意这是浅层的冻结对象, 如果有一个属性的值是个对象, 那这个对象中的属性是可以被修改的. 现在 JavaScript 也出现了 npm deep-freeze , Immutable.js 这些库来帮助你在 JavaScript 中实现不可变对象.
|
||||
|
||||
## Imperative and Declarative Programming(命令式和声明式编程)
|
||||
命令式编程, 描述一段代码的逻辑怎么被显式调用去改变程序的状态. 声明式编程, 描述一段代码的逻辑, 而不需要描述如何完成这段逻辑.
|
||||
@@ -46,9 +46,9 @@ JavaScript 可以同时被写为命令式和声明式编程方式, 但是随着
|
||||
- 声明式代码去管理副作用和执行命令式编程
|
||||
|
||||
## Hot and Cold Observables
|
||||
Observables 和数组类似, 只不过数组是被保存在内存中, 而Observables的每一个元素则是异步加入进来. 我们可以订阅这些 observables.
|
||||
Observables 和数组类似, 只不过数组是被保存在内存中, 而 Observables 的每一个元素则是异步加入进来. 我们可以订阅这些 observables.
|
||||
|
||||
Hot Observables 容易会被执行, 即使我们没有订阅它们. 比如说 用户的操作界面的 按钮点击事件, 鼠标移动, 窗口大小改变, 这些都是 Hot Observables. 而cold observable则是需要我们去订阅, 并且会在我们订阅的时候开始执行.
|
||||
Hot Observables 容易会被执行, 即使我们没有订阅它们. 比如说 用户的操作界面的 按钮点击事件, 鼠标移动, 窗口大小改变, 这些都是 Hot Observables. 而 cold observable 则是需要我们去订阅, 并且会在我们订阅的时候开始执行.
|
||||
|
||||
## 响应式编程 RP
|
||||
响应式编程, 可以看作是面向异步事件流的编程, 声明式的, 表述去做什么, 而不是怎么做.
|
||||
@@ -69,18 +69,18 @@ Hot Observables 容易会被执行, 即使我们没有订阅它们. 比如说
|
||||
|
||||
随着现在各种 SPA 框架的兴起, 理解数据流概念, 对于现在 JS 开发者越来越重要, React 被认为是单向数据流的典范, 使用 Model 作为唯一的数据来源, 控制 View 的渲染. 在 View 层用事件的方式通知 Model 更新, 在反应到 View 层的变化上. 数据沿着一个方向流动, UI 永远不会更新 Model, 而是通过事件或者 setState 方法.
|
||||
|
||||
在双向数据绑定中, 数据是在两个方向上流动的, JS可以更新 Model 数据, View 层 也可以更新 Model 数据. AngularJs 的1.x 版本是双向数据流的典型实现.
|
||||
在双向数据绑定中, 数据是在两个方向上流动的, JS 可以更新 Model 数据, View 层 也可以更新 Model 数据. AngularJs 的 1.x 版本是双向数据流的典型实现.
|
||||
|
||||
早在2009年, 双向绑定是 Angualr 最受欢迎的特性之一, 但是 Angular 把这一特性抛弃了. 现在很多流行的框架和库都使用了单向数据流(React,Angular,Inferno,Redux等). 单向数据流倡导的是清晰的架构, 数据流动更加清晰和易管理. 对于单向数据流来说说了点View自动更新数据的便利, 但也得到了清晰的数据流.
|
||||
早在 2009 年, 双向绑定是 Angualr 最受欢迎的特性之一, 但是 Angular 把这一特性抛弃了. 现在很多流行的框架和库都使用了单向数据流(React,Angular,Inferno,Redux 等). 单向数据流倡导的是清晰的架构, 数据流动更加清晰和易管理. 对于单向数据流来说说了点 View 自动更新数据的便利, 但也得到了清晰的数据流.
|
||||
|
||||
## JS框架中的变化侦测: 脏检查, getter 和 setter, 虚拟 DOM
|
||||
变化侦测对于现代 SPA应用来说很重要. 当用户更新一些内容时, 应用必须以一种方法知道这种变化, 并做出反应更新.
|
||||
## JS 框架中的变化侦测: 脏检查, getter 和 setter, 虚拟 DOM
|
||||
变化侦测对于现代 SPA 应用来说很重要. 当用户更新一些内容时, 应用必须以一种方法知道这种变化, 并做出反应更新.
|
||||
|
||||
AngularJS 1.x 使用的是脏检查的方式, 具体做法是对View 中涉及到的 Model 进行深度比较. 脏检查的优点在于它的简单和可预测, 不涉及到 API 和对象的变更. 但是正因为涉及到大量比较, 也很低效.
|
||||
AngularJS 1.x 使用的是脏检查的方式, 具体做法是对 View 中涉及到的 Model 进行深度比较. 脏检查的优点在于它的简单和可预测, 不涉及到 API 和对象的变更. 但是正因为涉及到大量比较, 也很低效.
|
||||
|
||||
Ember 和 Backbone 是使用getters 和 setters 来做变化侦测, 这样涉及到数据修改时, 都会触发变更事件. 而React 是使用了虚拟 Dom 来做变化侦测, React 通过 setState方法来通知变更, 使用虚拟 Dom 来比较是否发生了数据变化.
|
||||
Ember 和 Backbone 是使用 getters 和 setters 来做变化侦测, 这样涉及到数据修改时, 都会触发变更事件. 而 React 是使用了虚拟 Dom 来做变化侦测, React 通过 setState 方法来通知变更, 使用虚拟 Dom 来比较是否发生了数据变化.
|
||||
|
||||
## Web Components组件
|
||||
## Web Components 组件
|
||||
Web 组件是 Web 平台上可复用的基础组件, 而 Web Components 则定义了一些规范来实现这些可复用组件.
|
||||
规范包括:
|
||||
- 自定义元素
|
||||
@@ -88,20 +88,20 @@ Web 组件是 Web 平台上可复用的基础组件, 而 Web Components 则定
|
||||
- Shadow Dom
|
||||
- HTML imports 引入
|
||||
|
||||
Web Components本身并不能代替 SPA框架的功能, 但是它的想法和核心概念, 在很多 SPA 框架中都有体现.
|
||||
Web Components 本身并不能代替 SPA 框架的功能, 但是它的想法和核心概念, 在很多 SPA 框架中都有体现.
|
||||
|
||||
## Smart 和 Dumb 组件
|
||||
现在Web 的开发严重依赖组件, 而很多时候我们把组件分成 Smart 组件和 Dumb 组件.
|
||||
现在 Web 的开发严重依赖组件, 而很多时候我们把组件分成 Smart 组件和 Dumb 组件.
|
||||
|
||||
Smart 组件, 又叫容器组件, 在组件内处理各种业务逻辑, 通常也管理 Dumb 组件,响应 Dumb 组件的事件.
|
||||
|
||||
Dumb 组件, 又叫展示组件, 通常被写成纯函数, 依赖于外部的数据和方法, 专注于展现数据.
|
||||
|
||||
## JIT 编译
|
||||
Just-In-time(JIT)编译指的是代码的运行时, 被编译成机器代码的过程. 在JavaScript 运行时, JIT 能够找到代码的特定模式, 而这些模式可以让 JavaScript 更快的被执行.
|
||||
Just-In-time(JIT)编译指的是代码的运行时, 被编译成机器代码的过程. 在 JavaScript 运行时, JIT 能够找到代码的特定模式, 而这些模式可以让 JavaScript 更快的被执行.
|
||||
|
||||
## AOT 编译
|
||||
Ahead-Of-Time(AOT), 指的是编写的代码在运行之前, 被翻译成机器代码的过程. AOT给 tree shaking 带来了可能, 使用AOT 预编译, 对于生产环境下的代码有以下好处:
|
||||
Ahead-Of-Time(AOT), 指的是编写的代码在运行之前, 被翻译成机器代码的过程. AOT 给 tree shaking 带来了可能, 使用 AOT 预编译, 对于生产环境下的代码有以下好处:
|
||||
|
||||
- 更少的异步请求, 模板和样式内联在 JS 内
|
||||
- 更小的体积
|
||||
@@ -111,24 +111,24 @@ Ahead-Of-Time(AOT), 指的是编写的代码在运行之前, 被翻译成机器
|
||||
## Tree Shaking
|
||||
Tree Shaking 是指打包 JS 模块时, 通过对代码的静态分析, 排除掉不用的代码的机制.
|
||||
|
||||
Tree Shaking 技术建立在 ES2015模块的, import和 export上, 支持我们导入特定的内容,而不是整个库.
|
||||
Tree Shaking 技术建立在 ES2015 模块的, import 和 export 上, 支持我们导入特定的内容,而不是整个库.
|
||||
|
||||
```
|
||||
```plain
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
```
|
||||
|
||||
这样我们只导入了 BehaviorSubject, 而没有导入整个 Rxjs 库.
|
||||
# 3 精读
|
||||
文中讲到的现代 JavaScript 已经很多了, 再对理解的现代JavaScript补充几条:
|
||||
文中讲到的现代 JavaScript 已经很多了, 再对理解的现代 JavaScript 补充几条:
|
||||
|
||||
## Dependent injection(依赖注入)
|
||||
|
||||
通过控制反转,父级不需要关心子实现细节,将子类可能用到的实例都初始化好,由子类决定引入哪些依赖。还有一个好处是维持了单实例,这一点在数据流中尤为重要,如果 store 不是单例的,那数据流必然乱了套,既希望传给子类使用,又要维持单例,依赖注入是很好的解决方案。
|
||||
|
||||
## Symbol Reflect Proxy
|
||||
Symbol 是 ES6中加入的一种新的数据类型, 每一个 Symbol 都是独一无二的, 不与其它 Symbol 重复.
|
||||
Symbol 是 ES6 中加入的一种新的数据类型, 每一个 Symbol 都是独一无二的, 不与其它 Symbol 重复.
|
||||
|
||||
ES6中的 Proxy , 则是通过 Proxy 方法, 实现对于对象的一层拦截. 提供一种机制, 代理对象的操作. 而 Reflect 是一个内置的对象,它提供可拦截 JavaScript 操作的方法。方法与代理处理程序的方法相同。
|
||||
ES6 中的 Proxy , 则是通过 Proxy 方法, 实现对于对象的一层拦截. 提供一种机制, 代理对象的操作. 而 Reflect 是一个内置的对象,它提供可拦截 JavaScript 操作的方法。方法与代理处理程序的方法相同。
|
||||
|
||||
这三篇文章非常详细介绍了这三位 API:[symbol](https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/) [reflect](https://www.keithcirkel.co.uk/metaprogramming-in-es6-part-2-reflect/) [proxy](https://www.keithcirkel.co.uk/metaprogramming-in-es6-part-3-proxies/)
|
||||
|
||||
+13
-13
@@ -6,7 +6,7 @@
|
||||
|
||||
# 精读加密媒体扩展(Encrypted Media Extensions,EME)
|
||||
|
||||
本期精读的文章是: [W3C发布加密媒体扩展(Encrypted Media Extensions,EME)正式推荐标准](http://www.chinaw3c.org/2017-09-pressrelease-eme-recommendation.html)
|
||||
本期精读的文章是: [W3C 发布加密媒体扩展(Encrypted Media Extensions,EME)正式推荐标准](http://www.chinaw3c.org/2017-09-pressrelease-eme-recommendation.html)
|
||||
|
||||
感谢 [xekri](https://github.com/xekri) 提供 hacker news 上的热门讨论帖:[https://news.ycombinator.com/item?id=15278883](https://news.ycombinator.com/item?id=15278883)
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
>
|
||||
> —— 摘自《[HTML5 DRM 正式成为 Web 标准,EFF 辞职抗议](http://www.solidot.org/comments?sid=53884&op=reply&type=story)》
|
||||
|
||||
以上,是我17年9月19日晚收到的一条推送消息。我当时在写《[关于 React 系前端技术的思考](https://tingge.github.io/html/react-redux-reactrouter.html)》,可是它让我意识到,该关注下 <video /> 背后的故事了。
|
||||
17年下半年发生了两件有趣的撕 X 事件:Facebook 将部分开源项目的防专利流氓证书 “BSD + Pattern” 重新授权为 “MIT” 和 W3C 发布 HTML5 版权保护的 EME 推荐标准。一时,似乎著作权、版权和开源、分享,甚至普世、网络中立性,这些声音开始在不少人耳边盘绕。
|
||||
以上,是我 17 年 9 月 19 日晚收到的一条推送消息。我当时在写《[关于 React 系前端技术的思考](https://tingge.github.io/html/react-redux-reactrouter.html)》,可是它让我意识到,该关注下 <video /> 背后的故事了。
|
||||
17 年下半年发生了两件有趣的撕 X 事件:Facebook 将部分开源项目的防专利流氓证书 “BSD + Pattern” 重新授权为 “MIT” 和 W3C 发布 HTML5 版权保护的 EME 推荐标准。一时,似乎著作权、版权和开源、分享,甚至普世、网络中立性,这些声音开始在不少人耳边盘绕。
|
||||
|
||||
“无论如何,在当前的现实中,法律是保护著作权的。” 那么,我以 EME 为切入点,和大家聊聊 HTML 5 中如何保护知识产权吧。
|
||||
|
||||
@@ -34,24 +34,24 @@
|
||||
- EME:加密媒体扩展(Encrypted Media Extensions)是 W3C 提出的一种规范,用于在 Web 浏览器和 DRM 代理软件之间提供通信通道。
|
||||
|
||||
|
||||
- MSE:媒体源扩展(Media Source Extensions)是一项 [W3C](https://zh.wikipedia.org/wiki/%E4%B8%87%E7%BB%B4%E7%BD%91%E8%81%94%E7%9B%9F) 规范,它扩展了HTMLMediaElement,允许 JavaScript 生成媒体流以支持回放。这可以用于自适应流(adaptive streaming)及随时间变化的视频直播流(live streaming)等应用场景。
|
||||
- MSE:媒体源扩展(Media Source Extensions)是一项 [W3C](https://zh.wikipedia.org/wiki/%E4%B8%87%E7%BB%B4%E7%BD%91%E8%81%94%E7%9B%9F) 规范,它扩展了 HTMLMediaElement,允许 JavaScript 生成媒体流以支持回放。这可以用于自适应流(adaptive streaming)及随时间变化的视频直播流(live streaming)等应用场景。
|
||||
- CDM:内容解密模块(Content Decryption Module),客户端或者使用端软件或硬件提供的一个机制,可以播放加密内容。
|
||||
|
||||
#### 背景
|
||||
|
||||
长期以来,“多方利益”模式的 W3C ,以或标准化引领、或被各方优良实践推动再制定标准的方式,来影响着互联网的发展。
|
||||
|
||||
2011年时 Silverlight 、HTML5 及 Flash 还是最受热捧的 RIA (富互联网应用) 技术。当时,Silverlight 的PlayReady DRM、 Flash 的 Flash Media Rights Management(FMRM),在版权保护上已十分成熟。而 HTML5 还处于 <video> 未指明编码标准的萌芽状态、更谈不上版权保护。
|
||||
2011 年时 Silverlight 、HTML5 及 Flash 还是最受热捧的 RIA (富互联网应用) 技术。当时,Silverlight 的 PlayReady DRM、 Flash 的 Flash Media Rights Management(FMRM),在版权保护上已十分成熟。而 HTML5 还处于 <video> 未指明编码标准的萌芽状态、更谈不上版权保护。
|
||||
|
||||
随着移动互联网、视频直播、职能家电等等互联网快速发展,浏览器插件一度成为网络恶意攻击的重灾区,给网络用户安全性带来很大隐患。微软和许多企业都鼓励用户、开发者使用 HTML5 的通信协议,标准化通信可以极大增加网络安全性。其中包括 W3C 的 Media Source Extensions (MSE)、 Encrypted Media Extensions (EME),MPEG的 MPEG-DASH 和 Common Encryption (CENC)。
|
||||
随着移动互联网、视频直播、职能家电等等互联网快速发展,浏览器插件一度成为网络恶意攻击的重灾区,给网络用户安全性带来很大隐患。微软和许多企业都鼓励用户、开发者使用 HTML5 的通信协议,标准化通信可以极大增加网络安全性。其中包括 W3C 的 Media Source Extensions (MSE)、 Encrypted Media Extensions (EME),MPEG 的 MPEG-DASH 和 Common Encryption (CENC)。
|
||||
|
||||
终于,内容提供商(如 Netflix、Adobe、CableLabs 等)从 Flash、Silverlight 插件播放器过渡到统一的 HTML5 视频播放;各大浏览器公司(如 Google, Microsoft, Apple)也逐步抛弃了过时的媒体插件。
|
||||
|
||||
EME 作为 HTML 5 DRM 版权保护方案中的一员,虽然从2012年提案开始就颇多争议,但是事实上已被各浏览器以捆绑闭源的 CDM 的沙箱化方式“悄悄”分发。现在,W3C 只是给了它应有的名分罢了。
|
||||
EME 作为 HTML 5 DRM 版权保护方案中的一员,虽然从 2012 年提案开始就颇多争议,但是事实上已被各浏览器以捆绑闭源的 CDM 的沙箱化方式“悄悄”分发。现在,W3C 只是给了它应有的名分罢了。
|
||||
|
||||
#### EME 对 Web 产生的影响
|
||||
|
||||
W3C理事长 Tim Berners-Lee 在《[W3C Blog: 关于HTML5标准中的加密媒体扩展(EME)](http://www.chinaw3c.org/archives/1742/)》中阐述了 EME 对内容分发商、媒体、用户、开发者、安全技术研究人员的影响。
|
||||
W3C 理事长 Tim Berners-Lee 在《[W3C Blog: 关于 HTML5 标准中的加密媒体扩展(EME)](http://www.chinaw3c.org/archives/1742/)》中阐述了 EME 对内容分发商、媒体、用户、开发者、安全技术研究人员的影响。
|
||||
|
||||
对多数人的影响大概是,可以提供一个相对安全的在线环境使用户可以获取高品质商业级的 Web 音视频等内容,并便捷的就此进行在线互动。
|
||||
|
||||
@@ -69,7 +69,7 @@ W3C理事长 Tim Berners-Lee 在《[W3C Blog: 关于HTML5标准中的加密媒
|
||||
|
||||
以下是截取 caniuse 网站统计的 EME 和 ESM 的支持情况(点击图片可跳转到对应网址):
|
||||
|
||||
[ ](http://caniuse.com/#search=EME)
|
||||
[](http://caniuse.com/#search=EME)
|
||||
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ W3C理事长 Tim Berners-Lee 在《[W3C Blog: 关于HTML5标准中的加密媒
|
||||
|
||||
今天,在传输工作室生产的付费内容的时候,DRM 是必要的。这些内容必须防止被盗,因此 DRM 的代码和工作过程都向终端用户和开发者屏蔽了。解密过的内容不会离开解码层,因此也不会被拦截。
|
||||
|
||||
为了标准化 DRM 以及为各平台的实现提供一定的互通性,几个 Web 巨头一起创建了通用加密标准[Common Encryption (CENC)]() 和通用的多媒体加密扩展[Encrypted Media Extensions](),以便为多个 DRM 提供商(例如,EME 可用于 Edge 平台上的 Playready 和 Chrome 平台上的 Widewine)构建一套通用的 API,这些 API 能够从 DRM 授权模块读取视频内容加密密钥用于解密。
|
||||
为了标准化 DRM 以及为各平台的实现提供一定的互通性,几个 Web 巨头一起创建了通用加密标准[Common Encryption (CENC)](.) 和通用的多媒体加密扩展[Encrypted Media Extensions](.),以便为多个 DRM 提供商(例如,EME 可用于 Edge 平台上的 Playready 和 Chrome 平台上的 Widewine)构建一套通用的 API,这些 API 能够从 DRM 授权模块读取视频内容加密密钥用于解密。
|
||||
|
||||
CENC 声明了一套标准的加密和密钥映射方法,它可用于在多个 DRM 系统上解密相同的内容,只需要提供相同的密钥即可。
|
||||
|
||||
@@ -111,7 +111,7 @@ CENC 没有规定授权的发放、授权的格式、授权的存储、以及使
|
||||
|
||||
- index.html:模拟内容服务商视频播放网页,获取 EME 设置(本例中 eme.js),通过调用 MSE 模块(本例中 mse.js) 逐块加载视频片段并控制播放。
|
||||
- resources.js:模拟 License(Key) server,与 CDM 模块交互并提供解密媒体资源所需的 `key`;
|
||||
- media:模拟Key System 和 Packaging service。主要功能是提供一种内容保护(DRM)机制,实际应用中常见的 Key System 有 Clear Key、Playready、Widevine 等;另外,作为 Packaging Service,提供编码并加密媒体资源以供发布和播放使用。
|
||||
- media:模拟 Key System 和 Packaging service。主要功能是提供一种内容保护(DRM)机制,实际应用中常见的 Key System 有 Clear Key、Playready、Widevine 等;另外,作为 Packaging Service,提供编码并加密媒体资源以供发布和播放使用。
|
||||
- eme.js: 模拟 EME 通信模块。主要包括监听 MediaKeys 的 message 和 keystatuseschange 变化;发起证书请求;最后,通过 License(key) 解密 video/audio 流;
|
||||
- mse.js:模拟媒体源扩展模块,通过调用浏览器提供的 MSE API,来控制视频流播放逻辑。
|
||||
|
||||
@@ -120,7 +120,7 @@ CENC 没有规定授权的发放、授权的格式、授权的存储、以及使
|
||||
| 开源的视频播放器 | 个人点评 |
|
||||
| ---------------------------------------- | ---------------------------------------- |
|
||||
| [video.js](https://github.com/videojs/video.js) 和其[插件](https://github.com/videojs/video.js/wiki/Plugins#community-plugins)。设备检测与配置逻辑的 [videojs-contrib-hls](https://github.com/videojs/videojs-contrib-hls) 、广告 [videojs-contrib-ads](https://github.com/videojs/videojs-contrib-ads) | 免费开源的 HTML5 和 Flash 播放器,通过强大的插件应用于 [400,000 网站](https://trends.builtwith.com/media/VideoJS)。采用 Apache License, Version 2.0 授权 |
|
||||
| [JW Player](https://github.com/jwplayer/jwplayer) | 号称世界上最流行的嵌入播放器,应用于200万网站、每月13亿播放次数。采用 [Creative Commons license](http://creativecommons.org/licenses/by-nc-sa/3.0/) 授权 |
|
||||
| [JW Player](https://github.com/jwplayer/jwplayer) | 号称世界上最流行的嵌入播放器,应用于 200 万网站、每月 13 亿播放次数。采用 [Creative Commons license](http://creativecommons.org/licenses/by-nc-sa/3.0/) 授权 |
|
||||
| [Shaka Player](https://github.com/google/shaka-player) | Google 开源的基于 MSE + EME 的 JavaScript 库,支持 DASH、HLS 等。采用 Apache License 2.0 授权 |
|
||||
| [dash.js](https://github.com/Dash-Industry-Forum/dash.js) | 一个支持 MPEG DASH 的参考实现,适合研究学习。采用 BSD 授权 |
|
||||
|
||||
@@ -130,5 +130,5 @@ CENC 没有规定授权的发放、授权的格式、授权的存储、以及使
|
||||
|
||||
期待随着标准的发布,注重著作权、版权的互联网能够很快地向有序方向发展。
|
||||
|
||||
> 讨论地址是:[精读《W3C发布加密媒体扩展(Encrypted Media Extensions,EME)正式推荐标准》 · Issue #37 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/37)
|
||||
> 讨论地址是:[精读《W3C 发布加密媒体扩展(Encrypted Media Extensions,EME)正式推荐标准》 · Issue #37 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/37)
|
||||
> 如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。
|
||||
@@ -93,7 +93,7 @@ OOCSS 成为 css 的面向对象加强版,每个 class 只处理一件事:
|
||||
|
||||
## 3.4 SMACSS
|
||||
|
||||
### 为css分类
|
||||
### 为 css 分类
|
||||
|
||||
SMACSS 认为 css 有 5 个类别:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
本期精读的文章是:[Front End Performance Checklist 2017](https://www.smashingmagazine.com/2016/12/front-end-performance-checklist-2017-pdf-pages/)
|
||||
|
||||
现在随着 web 应用的复杂性日益增加,其性能优化就会显得尤为必要,同时会给性能指标分析带来新的挑战,因为性能指标之间的差异性非常大,这取决于使用的设备、浏览器、协议、网络类型以及其它能够对性能产生影响的潜在因素(如:CDN、ISP、cache、proxy、firewall、load balancer、server等)。
|
||||
现在随着 web 应用的复杂性日益增加,其性能优化就会显得尤为必要,同时会给性能指标分析带来新的挑战,因为性能指标之间的差异性非常大,这取决于使用的设备、浏览器、协议、网络类型以及其它能够对性能产生影响的潜在因素(如:CDN、ISP、cache、proxy、firewall、load balancer、server 等)。
|
||||
|
||||
# 1 引言
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
根据 [psychological research](https://www.smashingmagazine.com/2015/09/why-performance-matters-the-perception-of-time/#the-need-for-performance-optimization-the-20-rule) 指出,网站最少在速度上比别人快 20%,才能让用户感觉到比别人的更快。这个速度说的并不是整个页面的加载时间,而是[启动渲染时间](http://www.websiteoptimization.com/speed/tweak/start-render/),[首次有效渲染时间](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint),[交互时间](https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive)。
|
||||
|
||||
### 控制响应时间在100ms,控制帧速在60帧/秒
|
||||
### 控制响应时间在 100ms,控制帧速在 60 帧/秒
|
||||
|
||||
[RAIL performance model](https://www.smashingmagazine.com/2015/10/rail-user-centric-model-performance/) 提出的性能优化指标:务必在用户初始操作后的 100ms 内提供反馈。考虑到存在响应时间不足 100ms 的情况,页面最迟要在 50ms 的时候,把控制权交给主线程。
|
||||
|
||||
针对动画,其每一帧都需要在 16ms 内完成,这样才能保证每秒 60帧(一秒/60=16.6ms),如果可以的话最好能在 10ms 内完成。
|
||||
针对动画,其每一帧都需要在 16ms 内完成,这样才能保证每秒 60 帧(一秒/60=16.6ms),如果可以的话最好能在 10ms 内完成。
|
||||
|
||||
### 控制首次有效渲染时间在 1.25s,控制 SpeedIndex 在 1000
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
### 做好构建工具的选型
|
||||
|
||||
不要过度使用那些酷炫的技术栈,坚持选择适合开发环境的工具,如Grunt、Gulp、Webpack、PostCSS,或者组合起来的工具。只要这个工具运行的速度够快,而且没有给项目维护带来太大问题,就够了。
|
||||
不要过度使用那些酷炫的技术栈,坚持选择适合开发环境的工具,如 Grunt、Gulp、Webpack、PostCSS,或者组合起来的工具。只要这个工具运行的速度够快,而且没有给项目维护带来太大问题,就够了。
|
||||
|
||||
### 渐进增强
|
||||
|
||||
@@ -40,11 +40,11 @@
|
||||
|
||||
### 前端框架
|
||||
|
||||
最好使用那些支持服务器端渲染的框架,如Angular,React,Ember 等。所选的框架要保证是被广泛使用并且经过考验的。不同框架对性能有着不同程度的影响,同时对应着不同的优化策略,所以要清楚的了解所选择框架的每个方面。
|
||||
最好使用那些支持服务器端渲染的框架,如 Angular,React,Ember 等。所选的框架要保证是被广泛使用并且经过考验的。不同框架对性能有着不同程度的影响,同时对应着不同的优化策略,所以要清楚的了解所选择框架的每个方面。
|
||||
|
||||
### AMP 或 Instant Articles
|
||||
|
||||
- Google 的 [AMP](https://www.ampproject.org/) 技术会提供一套可靠的性能优化框架(基于免费的CDN网络)
|
||||
- Google 的 [AMP](https://www.ampproject.org/) 技术会提供一套可靠的性能优化框架(基于免费的 CDN 网络)
|
||||
- Facebook 的 [Instant Articles](https://instantarticles.fb.com/) 技术可以在 Facebook 上提升网站的性能。
|
||||
|
||||
### 合理利用 CDN
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
### micro-optimization 和 progressive booting
|
||||
|
||||
- 使用 [skeleton screens](https://twitter.com/lukew/status/665288063195594752) 代替loading indicator 展示
|
||||
- 使用 [skeleton screens](https://twitter.com/lukew/status/665288063195594752) 代替 loading indicator 展示
|
||||
- 使用能够加速 App 初始化渲染的技术,如 [tree-shaking](https://medium.com/@richavyas/aha-moments-from-ngconf-2016-part-1-angular-2-0-compile-cycle-6f462f68632e#.8b9afnsub)、[code-splitting](https://webpack.github.io/docs/code-splitting.html)
|
||||
- 针对[服务端渲染](https://www.smashingmagazine.com/2016/03/server-side-rendering-react-node-express)增加[预编译](https://www.lucidchart.com/techblog/2016/09/26/improving-angular-2-load-times/)环节
|
||||
- 使用 [Optimize.js](https://github.com/nolanlawson/optimize-js) 来加快初始加载速度,其原理是包装优先级高的调用函数
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
### 正确设置 HTTP cache header
|
||||
|
||||
需要正确设置 expires、cache-control、max-age以及其它 HTTP 缓存响应头。请使用 Cache-control: immutable,可以参考 [Heroku’s primer on HTTP caching headers](https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers)、[HTTP caching primer](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en)以及[缓存之最佳实践](https://jakearchibald.com/2016/caching-best-practices/)。
|
||||
需要正确设置 expires、cache-control、max-age 以及其它 HTTP 缓存响应头。请使用 Cache-control: immutable,可以参考 [Heroku’s primer on HTTP caching headers](https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers)、[HTTP caching primer](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en)以及[缓存之最佳实践](https://jakearchibald.com/2016/caching-best-practices/)。
|
||||
|
||||
### 减少使用第三方库,异步加载 JS
|
||||
|
||||
@@ -98,16 +98,16 @@
|
||||
- 可以使用 service worker 来达到字体缓存持久化
|
||||
- [关于如何快速入门字体优化的教程](https://pixelambacht.nl/2016/font-awesome-fixed/)
|
||||
|
||||
### 快速推送 critical CSS文件
|
||||
### 快速推送 critical CSS 文件
|
||||
|
||||
为了保证能够让浏览器快速渲染,会将所有用于首屏渲染的 CSS 文件整合成一个文件(即 [critical CSS](https://www.smashingmagazine.com/2015/08/understanding-critical-css/)),以 `<style>` 的行内形式内嵌到 `<head>`,这样可以减少 [critical 渲染路径](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/optimizing-critical-rendering-path?hl=en)。由于 HTTP 数据包大小的限制,因此 critical CSS 文件大小不能超过14KB。
|
||||
为了保证能够让浏览器快速渲染,会将所有用于首屏渲染的 CSS 文件整合成一个文件(即 [critical CSS](https://www.smashingmagazine.com/2015/08/understanding-critical-css/)),以 `<style>` 的行内形式内嵌到 `<head>`,这样可以减少 [critical 渲染路径](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/optimizing-critical-rendering-path?hl=en)。由于 HTTP 数据包大小的限制,因此 critical CSS 文件大小不能超过 14KB。
|
||||
|
||||
HTTP/2 协议可以让 critical CSS 用单个 CSS 文件存储,通过服务器推送 CSS 文件的传输方式来减少HTML 文件数据量,由于存在高速缓存问题,因此需要建立[带有缓存的 HTTP/2 服务器传输机制](https://css-tricks.com/cache-aware-server-push/)。
|
||||
HTTP/2 协议可以让 critical CSS 用单个 CSS 文件存储,通过服务器推送 CSS 文件的传输方式来减少 HTML 文件数据量,由于存在高速缓存问题,因此需要建立[带有缓存的 HTTP/2 服务器传输机制](https://css-tricks.com/cache-aware-server-push/)。
|
||||
|
||||
### tree-shaking 和 code-splitting 机制减轻负载
|
||||
|
||||
- [Tree-shaking](https://medium.com/@roman01la/dead-code-elimination-and-tree-shaking-in-javascript-build-systems-fb8512c86edf) 机制能够帮助清理生产环境中的冗余代码。可以通过 [Webpack2 Tree-Shaking](http://www.2ality.com/2015/12/webpack-tree-shaking.html) 机制来清理冗余的 exports 代码或者使用 [UnCSS](https://github.com/giakki/uncss)、[Helium](https://github.com/geuis/helium-css) 工具来清理冗余的CSS代码
|
||||
- [code splitting](https://webpack.github.io/docs/code-splitting.html) 机制是Webpack 的另一个特性,它能够将构建的代码分成多个 chunk,并且对 chunk 按需载入。只要在代码中定义了分离点(split point),Webpack 便会处理好相关的输出文件,不仅能够较少文件数据量,而且还能对代码做到按需载入。
|
||||
- [Tree-shaking](https://medium.com/@roman01la/dead-code-elimination-and-tree-shaking-in-javascript-build-systems-fb8512c86edf) 机制能够帮助清理生产环境中的冗余代码。可以通过 [Webpack2 Tree-Shaking](http://www.2ality.com/2015/12/webpack-tree-shaking.html) 机制来清理冗余的 exports 代码或者使用 [UnCSS](https://github.com/giakki/uncss)、[Helium](https://github.com/geuis/helium-css) 工具来清理冗余的 CSS 代码
|
||||
- [code splitting](https://webpack.github.io/docs/code-splitting.html) 机制是 Webpack 的另一个特性,它能够将构建的代码分成多个 chunk,并且对 chunk 按需载入。只要在代码中定义了分离点(split point),Webpack 便会处理好相关的输出文件,不仅能够较少文件数据量,而且还能对代码做到按需载入。
|
||||
- 用 [Rollup](http://rollupjs.org/) 来 export 代码也能够取得不错的效果
|
||||
|
||||
### 提升渲染性能
|
||||
@@ -131,7 +131,7 @@ HTTP/2 协议可以让 critical CSS 用单个 CSS 文件存储,通过服务器
|
||||
|
||||
从目前来看,浏览器对 HTTP/2 支持度还不错,使用 HTTP/2 后,就可以利用 service worker 以及 HTTP/2 的服务器推送功能来获取更显著的性能提升。
|
||||
|
||||
在项目进行 HTTPS 改造时,需要评估 HTTP/1.1 项目的用户基数,需要针对这类用户构建并发送符合HTTP2规范的报头。
|
||||
在项目进行 HTTPS 改造时,需要评估 HTTP/1.1 项目的用户基数,需要针对这类用户构建并发送符合 HTTP2 规范的报头。
|
||||
|
||||
### 正确部署 HTTP/2
|
||||
|
||||
@@ -142,7 +142,7 @@ HTTP/2 协议可以让 critical CSS 用单个 CSS 文件存储,通过服务器
|
||||
|
||||
### 确保服务器的安全性
|
||||
|
||||
需要检查是否[正确设置 HTTP 请求头部](https://securityheaders.io/),如 strict-transport-security,[使用 Snyk 工具](https://www.w3ctech.com/www.smashingmagazine.com/2016/01/eliminating-known-security-vulnerabilities-with-snyk/)排除已知的漏洞以及[使用 SSL Server Test](https://www.ssllabs.com/ssltest/) 网站来检查证书是否失效。 尽量保证从外部引入的插件以及 js 脚本的载入是通过 HTTPS 协议的,发起 HTTP 请求同时设置 strict-transport-security 以及 content-security-policy HTTP请求头。
|
||||
需要检查是否[正确设置 HTTP 请求头部](https://securityheaders.io/),如 strict-transport-security,[使用 Snyk 工具](https://www.w3ctech.com/www.smashingmagazine.com/2016/01/eliminating-known-security-vulnerabilities-with-snyk/)排除已知的漏洞以及[使用 SSL Server Test](https://www.ssllabs.com/ssltest/) 网站来检查证书是否失效。 尽量保证从外部引入的插件以及 js 脚本的载入是通过 HTTPS 协议的,发起 HTTP 请求同时设置 strict-transport-security 以及 content-security-policy HTTP 请求头。
|
||||
|
||||
### 服务器和 CDN 是否支持 HTTP/2
|
||||
|
||||
@@ -151,7 +151,7 @@ HTTP/2 协议可以让 critical CSS 用单个 CSS 文件存储,通过服务器
|
||||
### Brotli 或 Zopfli 压缩算法
|
||||
|
||||
- [Brotli](https://samsaffron.com/archive/2016/06/15/the-current-state-of-brotli-compression),是 Google 开源的无损数据格式,其压缩效率要远高于 Gzip 和 Deflate
|
||||
- [Zopfli压缩算法](https://blog.codinghorror.com/zopfli-optimization-literally-free-bandwidth/),能够将数据编码成 Deflate、Gzip、Zlib 数据格式。用 Zopfli 算法压缩过后的文件能够比同样用 Zlib 算法压缩的文件小 3%-8%
|
||||
- [Zopfli 压缩算法](https://blog.codinghorror.com/zopfli-optimization-literally-free-bandwidth/),能够将数据编码成 Deflate、Gzip、Zlib 数据格式。用 Zopfli 算法压缩过后的文件能够比同样用 Zlib 算法压缩的文件小 3%-8%
|
||||
|
||||
### 激活 OCSP stapling
|
||||
|
||||
@@ -186,7 +186,7 @@ HTTP/2 协议可以让 critical CSS 用单个 CSS 文件存储,通过服务器
|
||||
|
||||
### 持续监控
|
||||
|
||||
在进行快速、无限制的测试时,最好使用一个个人的WebPageTest实例。建立一个能自动预警的性能预算监听。建立自己的用户时间标记从而测量并监测具体商用的数据。使用SpeedCurve对性能的变化进行监控,同时利用New Relic获取WebPageTest没法提供的数据。SpeedTracker,Lighthouse和Calibre都是不错的选择。
|
||||
在进行快速、无限制的测试时,最好使用一个个人的 WebPageTest 实例。建立一个能自动预警的性能预算监听。建立自己的用户时间标记从而测量并监测具体商用的数据。使用 SpeedCurve 对性能的变化进行监控,同时利用 New Relic 获取 WebPageTest 没法提供的数据。SpeedTracker,Lighthouse 和 Calibre 都是不错的选择。
|
||||
|
||||
部署私密的 [WebPageTest](http://www.webpagetest.org/) 测试环境,有助于快速构建测试用例。针对性能开销大的环节建立自动报警机制,可以使用 [SpeedCurve](https://speedcurve.com/) 对性能的变化进行监控,利用 [New Relic](https://newrelic.com/browser-monitoring) 获取 WebPageTest 无法提供的数据。
|
||||
|
||||
@@ -251,9 +251,9 @@ render 部分包括 Recalculate Style 和 Layout,如果发现 render 部分耗
|
||||
|
||||
#### 降低样式计算和复杂度
|
||||
|
||||
添加或移除一个DOM元素、修改元素属性和样式类、应用动画效果等操作,都会引起DOM结构的改变,从而导致浏览器需要重新计算每个元素的样式、对页面或其一部分重新布局(多数情况下),这就是所谓的样式计算。
|
||||
添加或移除一个 DOM 元素、修改元素属性和样式类、应用动画效果等操作,都会引起 DOM 结构的改变,从而导致浏览器需要重新计算每个元素的样式、对页面或其一部分重新布局(多数情况下),这就是所谓的样式计算。
|
||||
|
||||
因此需要减少执行样式计算的元素的个数,降低样式选择器的复杂度,使用基于 class 的方式,如以BEM (Block, Element, Modifier)的方式编写 CSS 代码,能达到最好的样式计算的性能,因为这种方式建议对每个DOM元素都只使用一个样式class。
|
||||
因此需要减少执行样式计算的元素的个数,降低样式选择器的复杂度,使用基于 class 的方式,如以 BEM (Block, Element, Modifier)的方式编写 CSS 代码,能达到最好的样式计算的性能,因为这种方式建议对每个 DOM 元素都只使用一个样式 class。
|
||||
|
||||
#### 避免大规模、复杂的布局
|
||||
|
||||
@@ -280,7 +280,7 @@ Timeline 中绿色部分就是 Paint 部分,Summary 会展示绘制的总体
|
||||
#### 如何优化 Paint
|
||||
|
||||
- 提升元素渲染层为合成层,页面的绘制并非是在单层画面里完成的,浏览器的渲染原理,是浏览器将 DOM tree 映射成 GraphicsLayer tree,中间是经过了 RenderObject、RenderLayer 的一系列映射。元素所在的层提升为合成层后可以减少 Repaint
|
||||
- 使用 transform 或 opacity 实现动画,对于独立的合成层应用 transform 和 opacity 是不会触发 Repaint的,因此尽量对 transform 或 opactiy 应用动画来实现效果
|
||||
- 使用 transform 或 opacity 实现动画,对于独立的合成层应用 transform 和 opacity 是不会触发 Repaint 的,因此尽量对 transform 或 opactiy 应用动画来实现效果
|
||||
- 减少绘制区域,对于不需要重新绘制的区域应尽量避免绘制,已减少绘制区域,比如一个 fix 在页面顶部的固定不变的导航 header,在页面底部某个区域 Repaint 时,整个屏幕包括 fix 的 header 也会被重绘,而对于固定不变的区域,期望其并不会被重绘,因此可以通过之前的方法,将其提升为独立的合成层
|
||||
- 降低绘制复杂度,对于无法避免的 Paint,需要尽可能的减少 Paint 的消耗,有些效果的 Paint 代价十分昂贵,比如绘制一个阴影可能就比绘制一个边框更加耗时,因此开发过程中,需要研究能够实现相同的效果,同时却能达到更小的 Paint 消耗的方法
|
||||
|
||||
@@ -311,6 +311,6 @@ Timeline 中绿色部分就是 Paint 部分,Summary 会展示绘制的总体
|
||||
|
||||
现在随着 web 应用的复杂性日益增加,其性能优化的重要性越来越突出,且性能优化的方法、技巧、工具也越来越丰富和复杂,本文所展示的内容仅仅只是管中窥豹,希望读者们可以在此讨论一些在实际场景中的性能优化问题以及解决方案。
|
||||
|
||||
> 讨论地址是:[精读《2017前端性能优化备忘录》 · Issue #39 · dt-fe/weekly](http://github.com/dt-fe/weekly/issues/39)
|
||||
> 讨论地址是:[精读《2017 前端性能优化备忘录》 · Issue #39 · dt-fe/weekly](http://github.com/dt-fe/weekly/issues/39)
|
||||
|
||||
> 如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
我为什么要选这篇文章呢?
|
||||
|
||||
sessionstack最近接连发了好几篇文章, 深入探讨JS, 以及 JS 中一些内部原理. 文中也讲到了, 伴随深入了解 JS 中的一些工作原理, 才有可能写出更好的代码和程序.
|
||||
sessionstack 最近接连发了好几篇文章, 深入探讨 JS, 以及 JS 中一些内部原理. 文中也讲到了, 伴随深入了解 JS 中的一些工作原理, 才有可能写出更好的代码和程序.
|
||||
|
||||
而 JS 中的内存管理, 我的感觉就像 JS 中的一门副科, 我们平时不会太重视, 但是一旦出问题又很棘手. 所以可以通过平时多了解一些 JS 中内存管理问题, 在写代码中通过一些习惯, 避免内存泄露的问题.
|
||||
|
||||
@@ -23,11 +23,11 @@ sessionstack最近接连发了好几篇文章, 深入探讨JS, 以及 JS 中一
|
||||
2. 使用分配到的内存(读, 写)
|
||||
3. 不需要时将其释放/归还
|
||||
|
||||
在 C语言中, 有专门的内存管理接口, 像`malloc()` 和 `free()`. 而在 JS 中, 没有专门的内存管理接口, 所有的内存管理都是"自动"的. JS 在创建变量时, 自动分配内存, 并在不使用的时候, 自动释放. 这种"自动"的内存回收, 造成了很多 JS 开发并不关心内存回收, 实际上, 这是错误的.
|
||||
在 C 语言中, 有专门的内存管理接口, 像`malloc()` 和 `free()`. 而在 JS 中, 没有专门的内存管理接口, 所有的内存管理都是"自动"的. JS 在创建变量时, 自动分配内存, 并在不使用的时候, 自动释放. 这种"自动"的内存回收, 造成了很多 JS 开发并不关心内存回收, 实际上, 这是错误的.
|
||||
|
||||
## JS 中的内存回收
|
||||
### 引用
|
||||
垃圾回收算法主要依赖于引用的概念. 在内存管理的环境中, 一个对象如果有访问另一个对象的权限(隐式或者显式), 叫做一个对象引用另一个对象. 例如: 一个Javascript对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用).
|
||||
垃圾回收算法主要依赖于引用的概念. 在内存管理的环境中, 一个对象如果有访问另一个对象的权限(隐式或者显式), 叫做一个对象引用另一个对象. 例如: 一个 Javascript 对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用).
|
||||
|
||||
### 引用计数垃圾收集
|
||||
这是最简单的垃圾收集算法.此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”. 如果没有引用指向该对象(零引用, 对象将被垃圾回收机制回收.
|
||||
@@ -64,13 +64,13 @@ window.onload = function(){
|
||||
### 标记-清除算法
|
||||
这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”.
|
||||
|
||||
这个算法假定设置一个叫做根`root`的对象(在Javascript里,根是全局对象). 定期的, 垃圾回收器将从根开始, 找所有从根开始引用的对象, 然后找这些对象引用的对象, 从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象.
|
||||
这个算法假定设置一个叫做根`root`的对象(在 Javascript 里,根是全局对象). 定期的, 垃圾回收器将从根开始, 找所有从根开始引用的对象, 然后找这些对象引用的对象, 从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象.
|
||||
|
||||
从2012年起, 所有现代浏览器都使用了标记-清除内存回收算法。所有对JavaScript垃圾回收算法的改进都是基于标记-清除算法的改进.
|
||||
从 2012 年起, 所有现代浏览器都使用了标记-清除内存回收算法。所有对 JavaScript 垃圾回收算法的改进都是基于标记-清除算法的改进.
|
||||

|
||||
|
||||
### 自动 GC 的问题
|
||||
尽管自动 GC 很方便, 但是我们不知道GC 什么时候会进行. 这意味着如果我们在使用过程中使用了大量的内存, 而 GC 没有运行的情况下, 或者 GC 无法回收这些内存的情况下, 程序就有可能假死, 这个就需要我们在程序中手动做一些操作来触发内存回收.
|
||||
尽管自动 GC 很方便, 但是我们不知道 GC 什么时候会进行. 这意味着如果我们在使用过程中使用了大量的内存, 而 GC 没有运行的情况下, 或者 GC 无法回收这些内存的情况下, 程序就有可能假死, 这个就需要我们在程序中手动做一些操作来触发内存回收.
|
||||
|
||||
### 什么是内存泄露?
|
||||
本质上讲, 内存泄露就是不再被需要的内存, 由于某种原因, 无法被释放.
|
||||
@@ -94,11 +94,11 @@ function foo() {
|
||||
// Foo 被调用时, this 指向全局变量(window)
|
||||
foo();
|
||||
```
|
||||
在这种情况下调用`foo`, this被指向了全局变量`window`, 意外的创建了全局变量.
|
||||
在这种情况下调用`foo`, this 被指向了全局变量`window`, 意外的创建了全局变量.
|
||||
|
||||
我们谈到了一些意外情况下定义的全局变量, 代码中也有一些我们明确定义的全局变量. 如果使用这些全局变量用来暂存大量的数据, 记得在使用后, 对其重新赋值为 null.
|
||||
#### 2. 未销毁的定时器和回调函数
|
||||
在很多库中, 如果使用了观察着模式, 都会提供回调方法, 来调用一些回调函数. 要记得回收这些回调函数. 举一个 setInterval的例子.
|
||||
在很多库中, 如果使用了观察者模式, 都会提供回调方法, 来调用一些回调函数. 要记得回收这些回调函数. 举一个 setInterval 的例子.
|
||||
```javascript
|
||||
var serverData = loadData();
|
||||
setInterval(function() {
|
||||
@@ -133,7 +133,7 @@ setInterval(replaceThing, 1000);
|
||||
|
||||
这个范例的关键在于, 闭包之间是共享作用域的, 尽管`unused`可能一直没有被调用, 但是`someMethod` 可能会被调用, 就会导致内存无法对其进行回收. 当这段代码被反复执行时, 内存会持续增长.
|
||||
|
||||
该问题的更多描述可见[Meteor团队的这篇文章](https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156).
|
||||
该问题的更多描述可见[Meteor 团队的这篇文章](https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156).
|
||||
#### 4. DOM 引用
|
||||
很多时候, 我们对 Dom 的操作, 会把 Dom 的引用保存在一个数组或者 Map 中.
|
||||
```Javascript
|
||||
@@ -153,7 +153,7 @@ function removeImage() {
|
||||
另外需要注意的一个点是, 对于一个 Dom 树的叶子节点的引用. 举个例子: 如果我们引用了一个表格中的`td`元素, 一旦在 Dom 中删除了整个表格, 我们直观的觉得内存回收应该回收除了被引用的 `td`外的其他元素. 但是事实上, 这个`td` 元素是整个表格的一个子元素, 并保留对于其父元素的引用. 这就会导致对于整个表格, 都无法进行内存回收. 所以我们要小心处理对于 Dom 元素的引用.
|
||||
# 3 精读
|
||||
|
||||
ES6中引入`WeakSet` 和 `WeakMap`两个新的概念, 来解决引用造成的内存回收问题. `WeakSet` 和 `WeakMap`对于值的引用可以忽略不计, 他们对于值的引用是弱引用,内存回收机制, 不会考虑这种引用. 当其他引用被消除后, 引用就会从内存中被释放.
|
||||
ES6 中引入`WeakSet` 和 `WeakMap`两个新的概念, 来解决引用造成的内存回收问题. `WeakSet` 和 `WeakMap`对于值的引用可以忽略不计, 他们对于值的引用是弱引用,内存回收机制, 不会考虑这种引用. 当其他引用被消除后, 引用就会从内存中被释放.
|
||||
|
||||
JS 这类高级语言,隐藏了内存管理功能。但无论开发人员是否注意,内存管理都在那,所有编程语言最终要与操作系统打交道,在内存大小固定的硬件上工作。不幸的是,即使不考虑垃圾回收对性能的影响,2017 年最新的垃圾回收算法,也无法智能回收所有极端的情况。
|
||||
|
||||
@@ -161,7 +161,7 @@ JS 这类高级语言,隐藏了内存管理功能。但无论开发人员是
|
||||
|
||||
所以在 JS 这类高级语言中,有必要掌握基础内存分配原理,在对内存敏感的场景,比如 nodejs 代码做严格检查与优化。谨慎使用 dom 操作、主动删除没有业务意义的变量、避免提前优化、过度优化,在保证代码可读性的前提下,利用性能监控工具,通过调用栈定位问题代码。
|
||||
|
||||
同时对于如何利用 chrome调试工具, 分析内存泄露的方法和技巧. 可以参考上期精读[精读《2017前端性能优化备忘录》](https://zhuanlan.zhihu.com/p/30349982)
|
||||
同时对于如何利用 chrome 调试工具, 分析内存泄露的方法和技巧. 可以参考上期精读[精读《2017 前端性能优化备忘录》](https://zhuanlan.zhihu.com/p/30349982)
|
||||
|
||||
# 4 总结
|
||||
|
||||
@@ -174,4 +174,4 @@ JS 这类高级语言,隐藏了内存管理功能。但无论开发人员是
|
||||
|
||||
|
||||
|
||||
参考文章: [MDN 的内存管理介绍](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_Management)
|
||||
参考文章: [MDN 的内存管理介绍](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_Management)
|
||||
@@ -6,13 +6,13 @@
|
||||
|
||||
我为什么要选这篇文章呢?
|
||||
|
||||
sessionstack最近接连发了好几篇文章, 深入探讨JS, 以及 JS 中一些内部原理. 文中也讲到了, 伴随深入了解 JS 中的一些工作原理, 才有可能写出更好的代码和程序.
|
||||
sessionstack 最近接连发了好几篇文章, 深入探讨 JS, 以及 JS 中一些内部原理. 文中也讲到了, 伴随深入了解 JS 中的一些工作原理, 才有可能写出更好的代码和程序.
|
||||
|
||||
而 JS 中 Event Loop, 我的感觉就像 JS 中的一门内科, 我们平时只注意外科创伤,却忽视了内科问题往往容易莫名其妙的生病。了解 JS Event Loop 的原理,对 `setTimeout` `Promise` 这种基础概念不再浮在表层,可以写出更可靠的代码,如果你是前端新人,不要总是因为这个问题挂在一面 :p。
|
||||
|
||||
# 2 内容概要
|
||||
|
||||
从前我对 Event Loop 的理解也并不透彻,通过仔细阅读此文后, Event Loop 、宿主环境、js线程三者之间关系更加透明了,希望读者读完后也能有所体会。
|
||||
从前我对 Event Loop 的理解也并不透彻,通过仔细阅读此文后, Event Loop 、宿主环境、js 线程三者之间关系更加透明了,希望读者读完后也能有所体会。
|
||||
|
||||
文中 Promise、async/await 部分就忽略了,本篇重点介绍 Event Loop 。
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
本期精读的文章是:[30行js代码创建神经网络](https://medium.freecodecamp.org/how-to-create-a-neural-network-in-javascript-in-only-30-lines-of-code-343dafc50d49)。
|
||||
本期精读的文章是:[30 行 js 代码创建神经网络](https://medium.freecodecamp.org/how-to-create-a-neural-network-in-javascript-in-only-30-lines-of-code-343dafc50d49)。
|
||||
|
||||
懒得看文章?没关系,稍后会附上文章内容概述,同时,更希望能通过阅读这一期的精读,穿插着深入阅读原文。
|
||||
|
||||
## 1 引言
|
||||

|
||||
|
||||
自从Alpha Go 打败了李世石,大家对深度学习的体感更加的强烈,人工智能也越来越多的出现在大家的生活之中。很多人也会谈论,程序员什么时候会被人工智能给替代?与其慌张,在人工智能的潮流下,不断学习新的人工智能相关技术,武装自己,才是硬道理。 本文介绍了如何使用[Synaptic.js](https://synaptic.juancazala.com/#/) 创建简单的神经网络,解决异或运算的问题。
|
||||
自从 Alpha Go 打败了李世石,大家对深度学习的体感更加的强烈,人工智能也越来越多的出现在大家的生活之中。很多人也会谈论,程序员什么时候会被人工智能给替代?与其慌张,在人工智能的潮流下,不断学习新的人工智能相关技术,武装自己,才是硬道理。 本文介绍了如何使用[Synaptic.js](https://synaptic.juancazala.com/#/) 创建简单的神经网络,解决异或运算的问题。
|
||||
|
||||
## 2 内容概要
|
||||
|
||||
### 神经网络中的神经元和突触
|
||||
|
||||
对神经网络有所了解的人都知道,神经网络就是构建类似人脑的神经系统,在人脑的神经系统中,存在一种非常重要的细胞,叫神经元。在神经网络中,你可以把神经元理解为一个函数,它接受一些输入返回一些输出结果,其中[Sigmoid神经元](https://en.wikipedia.org/wiki/Sigmoid_function)是一种非常常用的神经元,这种神经元以 Sigmoid 函数 作为[激活函数](https://www.zhihu.com/question/22334626)。Sigmoid 函数接受任意的数值,输出 `0` 到 `1` 之间的值,大家可以看看常见的几种 Sigmoid 函数的函数曲线。
|
||||
对神经网络有所了解的人都知道,神经网络就是构建类似人脑的神经系统,在人脑的神经系统中,存在一种非常重要的细胞,叫神经元。在神经网络中,你可以把神经元理解为一个函数,它接受一些输入返回一些输出结果,其中[Sigmoid 神经元](https://en.wikipedia.org/wiki/Sigmoid_function)是一种非常常用的神经元,这种神经元以 Sigmoid 函数 作为[激活函数](https://www.zhihu.com/question/22334626)。Sigmoid 函数接受任意的数值,输出 `0` 到 `1` 之间的值,大家可以看看常见的几种 Sigmoid 函数的函数曲线。
|
||||
|
||||

|
||||
|
||||
知道了 Sigmoid 函数了,我们可以看一个具体的 **Sigmoid神经元** 例子。
|
||||
知道了 Sigmoid 函数了,我们可以看一个具体的 **Sigmoid 神经元** 例子。
|
||||
|
||||

|
||||
|
||||
@@ -71,11 +71,11 @@ for (var i = 0; i < 20000; i++) {
|
||||
}
|
||||
```
|
||||
|
||||
简单而言,运行 `myNetwork.activate([0,0])` 时,`[0, 0]`是输入值,它对应的异或运算的结果是false, 也就是 `0`。 这个是前向的传播,所以称为 **激活** 网络,每次前向传播之后,我们需要做一次**反向传播**来更新权重和偏差。
|
||||
简单而言,运行 `myNetwork.activate([0,0])` 时,`[0, 0]`是输入值,它对应的异或运算的结果是 false, 也就是 `0`。 这个是前向的传播,所以称为 **激活** 网络,每次前向传播之后,我们需要做一次**反向传播**来更新权重和偏差。
|
||||
|
||||
反向传播就是通过这行代码来做的: `myNetwork.propagate(learningRate, [0])`,其中 `learningRate `是告诉神经网络如何调整权重的常量,第二个参数 `[0]`是异或运算的结果。
|
||||
|
||||
经过20000次学习,我们得到如下的结果:
|
||||
经过 20000 次学习,我们得到如下的结果:
|
||||
|
||||
```js
|
||||
console.log(myNetwork.activate([0,0]));
|
||||
@@ -129,7 +129,7 @@ console.log(myNetwork.activate([1,1]));
|
||||
|
||||
## 4. 总结
|
||||
|
||||
本文介绍了使用[Synaptic.js](https://synaptic.juancazala.com/#/) 创建简单的神经网络,解决异或运算的问题过程,也对**反向传播**的过程进行了简单的解释。文中实现神经网络的代码非常简单,包行注释也不超过30行,但是只会代码会有点囫囵吞枣的感觉,大家可以参考文章中给的引文,了解更多的算法原理。
|
||||
本文介绍了使用[Synaptic.js](https://synaptic.juancazala.com/#/) 创建简单的神经网络,解决异或运算的问题过程,也对**反向传播**的过程进行了简单的解释。文中实现神经网络的代码非常简单,包行注释也不超过 30 行,但是只会代码会有点囫囵吞枣的感觉,大家可以参考文章中给的引文,了解更多的算法原理。
|
||||
|
||||
### 相关资料
|
||||
|
||||
@@ -144,6 +144,6 @@ console.log(myNetwork.activate([1,1]));
|
||||
|
||||
### 更多讨论
|
||||
|
||||
> 讨论地址是:[精读《30行js代码创建神经网络》 · Issue #45 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/45)
|
||||
> 讨论地址是:[精读《30 行 js 代码创建神经网络》 · Issue #45 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/45)
|
||||
|
||||
**如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。**
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
本篇是 《框架实现》。
|
||||
|
||||
本周精读的文章是 [dob文档](https://dobjs.github.io/dob-docs/v2/guide/introduction.html),如果不熟悉 API,可以简单读一读,文中有些地方会提到一些函数。
|
||||
本周精读的文章是 [dob 文档](https://dobjs.github.io/dob-docs/v2/guide/introduction.html),如果不熟悉 API,可以简单读一读,文中有些地方会提到一些函数。
|
||||
|
||||
## 1 引言
|
||||
|
||||
+3
-3
@@ -88,7 +88,7 @@ git 的版本控制实际就是对文件进行管理和控制,其管理方法
|
||||
|
||||

|
||||
|
||||
其实是 40位 hash-key 的前两位作为目录名,后 38位 作为文件名,这个对象里面的内容就是 file1.js 的内容,可以查看该对象的内容和类型。
|
||||
其实是 40 位 hash-key 的前两位作为目录名,后 38 位 作为文件名,这个对象里面的内容就是 file1.js 的内容,可以查看该对象的内容和类型。
|
||||
|
||||
执行 git cat-file -p [hash-key] 可以查看已经存在的 object 对象内容;
|
||||
|
||||
@@ -141,7 +141,7 @@ blob 对象用于存储对应文件的内容,tree 对象可以理解为存储
|
||||
|
||||

|
||||
|
||||
目前每个目录里有一个对象,共5个对象,之前的总体 tree 图只包含了4个对象,执行 git log 查看 commit 记录。
|
||||
目前每个目录里有一个对象,共 5 个对象,之前的总体 tree 图只包含了 4 个对象,执行 git log 查看 commit 记录。
|
||||
|
||||

|
||||
|
||||
@@ -173,7 +173,7 @@ git 版本控制住要就是围绕这三类内部对象展开,分别为 blob
|
||||
|
||||
# 4 总结
|
||||
|
||||
本文从一个实际问题即如何使用 git 维护丢失的 commit 入手,并给出相应的解决思路和方案,以及通过git 内部三种对象来分析其内部工作机制,希望能过解决读者们对 git 存在困惑的地方,同时也希望读者们积极参与每周精度的讨论,各抒己见,分享自身在实际工作中遇到的问题及其解决思路。
|
||||
本文从一个实际问题即如何使用 git 维护丢失的 commit 入手,并给出相应的解决思路和方案,以及通过 git 内部三种对象来分析其内部工作机制,希望能过解决读者们对 git 存在困惑的地方,同时也希望读者们积极参与每周精度的讨论,各抒己见,分享自身在实际工作中遇到的问题及其解决思路。
|
||||
|
||||
> 讨论地址是:[精读《When You “Git” in Trouble - a Version Control Story》 · Issue #49 · dt-fe/weekly](http://github.com/dt-fe/weekly/issues/49)
|
||||
|
||||
+6
-6
@@ -1,9 +1,9 @@
|
||||
# 摘要
|
||||
本期精读文章以一个简单的例子,抽丝剥茧细数讲述如何面向用户可视化设计,探索用户最终的目的,化繁为简,化多为少,揉和N张图至一张图,并传达更多的深意。本文原文:http://www.storytellingwithdata.com/blog/2017/12/14/how-we-position-and-what-we-compare
|
||||
本期精读文章以一个简单的例子,抽丝剥茧细数讲述如何面向用户可视化设计,探索用户最终的目的,化繁为简,化多为少,揉和 N 张图至一张图,并传达更多的深意。本文原文:http://www.storytellingwithdata.com/blog/2017/12/14/how-we-position-and-what-we-compare
|
||||
|
||||
下面是案例优化的具体步骤:
|
||||
# 庖丁解牛 - 可视化案例优化
|
||||
可视化的时候,一定要优先考虑用户能够比较什么,然后把这些数据放到一个基准上,并把要比较的东西放到最近的地方。这样用户就可以快速简便的处理比较数据。图中有一系列类似分面的柱状图,代表了 Q1 ~ Q3 三个季度的账户 targeted筛选 -> engaged订阅 -> pitched投放 -> adopted采用的四个状态的百分比,这四个状态是呈漏斗式的数据,分别是上一个数据的子集。这个案列中,用户希望能够在一张图中比较所有的数据。如下是基础原始图:
|
||||
可视化的时候,一定要优先考虑用户能够比较什么,然后把这些数据放到一个基准上,并把要比较的东西放到最近的地方。这样用户就可以快速简便的处理比较数据。图中有一系列类似分面的柱状图,代表了 Q1 ~ Q3 三个季度的账户 targeted 筛选 -> engaged 订阅 -> pitched 投放 -> adopted 采用的四个状态的百分比,这四个状态是呈漏斗式的数据,分别是上一个数据的子集。这个案列中,用户希望能够在一张图中比较所有的数据。如下是基础原始图:
|
||||
<div>
|
||||
<img src="http://images2017.cnblogs.com/blog/395937/201712/395937-20171224171406912-710179221.png" width = "500" height = "500" alt="图片名称" align=center />
|
||||
</div>
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
1. 左上角,我们可以对比 Q1 北美 的四条柱状图,因为这四个数据相邻,并且是在一个坐标系中。
|
||||
|
||||
2. 最上面一排,我们可以对比 Q1 北美和EMEA engaged订阅(两条紫色柱子)的数据,这个对比需要我们横向用手指去比较,需要参照物,存在一定的门槛。
|
||||
2. 最上面一排,我们可以对比 Q1 北美和 EMEA engaged 订阅(两条紫色柱子)的数据,这个对比需要我们横向用手指去比较,需要参照物,存在一定的门槛。
|
||||
|
||||
基于第2点,我们可以考虑转换下思维,转换下数据呈现的类型可以更快速的比较。文中作者从自己在银行的职业生涯中发现线性图形的角度可以更快速的比较。所以就有了下面一张图
|
||||
基于第 2 点,我们可以考虑转换下思维,转换下数据呈现的类型可以更快速的比较。文中作者从自己在银行的职业生涯中发现线性图形的角度可以更快速的比较。所以就有了下面一张图
|
||||
<div>
|
||||
<img src="http://images2017.cnblogs.com/blog/395937/201712/395937-20171224215602928-500155458.png" width = "500" height = "500" alt="图片名称" align=center />
|
||||
</div>
|
||||
@@ -34,9 +34,9 @@
|
||||
|
||||
1. 每个阶段,北美的数据都比其他地区低
|
||||
|
||||
2. 相比其他区域,为什么APAC 的传播度有了突然的提升?
|
||||
2. 相比其他区域,为什么 APAC 的传播度有了突然的提升?
|
||||
|
||||
3. 最需要关注Q3的数据,以及最终阶段的数据
|
||||
3. 最需要关注 Q3 的数据,以及最终阶段的数据
|
||||
|
||||
# 最后
|
||||
从这篇文章的可视化案例优化样板,可以总结出以下步骤:
|
||||
@@ -0,0 +1,161 @@
|
||||
本期精读的文章是: [coinhive 官方文档](https://coinhive.com)及[Monero 官方文档](https://getmonero.org/)
|
||||
|
||||
懒得看文章?没关系。
|
||||
|
||||
咦,怎么是官方文档?
|
||||
|
||||
本期精读有所不同,注重实操,先操作获取感性认识,然后再介绍相关的概念,由浅入深,力求不纠缠细节,但不遮盖环节。阅读本文需要对加密货币有一些基本常识 (如果你是一个开发者但是完全没了解过加密货币,可以参考[这里](http://piotrpasich.com/introduction-bitcoin-for-developers/))。希望同学们看完本文能对加密货币领域有一个更深更切实的感受。如果要了解更多细节,文末总结的延伸阅读链接列表是最好的开始。
|
||||
|
||||
要注意一点,文中很多说明是默认基于 XMR 和 BTC 的,他们两个又同源,机制非常相似。**所以很多命题判断并不适用于所有的成千上万的加密货币.** 正相反,新的币种层出不穷,几乎所有的惯例都被打破,所有可能性都被尝试。这一点以下不再做说明。
|
||||
|
||||
# 1 引言
|
||||
首先,干货。10 行代码,5 分钟,不需部署不需构建直接浏览器开挖。
|
||||
|
||||
- 本地创建文件 test.html,粘贴如下代码:
|
||||
```plain
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mining</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="coinhive-miner"
|
||||
style="width: 256px; height: 310px"
|
||||
data-key="MUtCJzIDhrs01ERrf3qlqdawo35N0CYD">
|
||||
<em>Loading...</em>
|
||||
</div>
|
||||
<script src="https://authedmine.com/lib/simple-ui.min.js" async></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
- 本地双击打开。等待 JS 加载,点击 widget "Start Mining"。开始挖矿! 如下图
|
||||
|
||||

|
||||
|
||||
不错,数字已经在跳动,风扇开始工作,永无尽头的挖矿已经开始了。那么重要的是,挖出来的加密货币在哪呢?原来上面的代码里用的还是我的 API key,所以还没挖到你自己那里,所以请继续下面的步骤:
|
||||
|
||||
- 在 coinhive 注册账号并登陆。它是做什么的?别急,后面会详细讲。在 `coinhive/settings` 找到自己的 `API keypair`,把 `public key` 复制出来,形如 `MUtCJzIDhrs01ERrf3qlqdawo35N0CYD`
|
||||
|
||||
- 替换上面代码中的 data-key 部分,重新开始挖矿。好了,现在挖出的 Monero (这是啥?详见下一节) 已经会到你自己的 coinhive 账户中。用下图来说明,你名下总计算过的 Hash 个数为 264K,当前难度换算为 0.00002 个 Monero(Symbol:XMR)。当前难度为 66G 一个 block,一个 block reward 5.87 XMR,得到一个 XMR 是 11.268G。264K/11.268G = 0.0000234。这就是你目前的收益。
|
||||
|
||||

|
||||
|
||||
- 查 bitfinex 可得现在 XMR 价格在 375 美元 (当你看到本文的时候,价格可能早就又波动到不知哪里去了),所以你 (以及你忠实勤劳的电脑) 获得的实际收益为 0.000234 * 375 USD = 0.008775 USD,快到一分钱了 :)
|
||||
|
||||
怎么样,有没有一种浏览器点开即玩一刀 999 级的感觉。以上操作的便捷直接,是建立在无数前人大量的开发和基础设施建设之上的。越是领域早期的工作,越步履维艰,收货也越丰厚。如今加密货币已经走到了一个成年期,逐渐稳定成熟起来。
|
||||
|
||||
接下来我们聚焦到上面过程的每个环节,了解下拼图的每一块是怎样被构成全图的。
|
||||
|
||||
# 2 聚焦
|
||||
让我们从最终端最接近用户的环节开始,逐一聚焦,最后走完整条链路。
|
||||
|
||||
## 2.1 从浏览器说起
|
||||
本文标题叫浏览器挖矿,也是和贴合前端的部分。那么为什么可以在浏览器里挖矿?为什么可以很多用户在多个终端浏览器同时为同一个人 (你) 挖矿?
|
||||
|
||||
我们知道,挖矿是对加密货币产生机制的俗称。主流大多采取 Proof of Work (PoW) 机制。最常见的 PoW 方式就是由网络中所有节点作为矿工,每个节点都基于 blockchain 前面 block 已有信息计算一个新信息。这个新信息的计算方式往往是某种 hash function,并且人为地被设置为需要巨大计算力和时间才能完成 (其具体难度一般也会实时调整)。当一个节点幸运地 (也依靠强大的算力) 第一个计算出结果后,会把这个结果广播到网络中。其他所有节点会验证这个结果 (我们知道非对称加密算法,验证便宜而计算昂贵),一旦证实就会停下手里的计算,承认这个计算结果。新的计算结果创造出新的块,区块链的高度增加一层,然后计算继续下去。每一个块的生成一般在 2-10 分钟。这个过程就被叫做挖矿.
|
||||
|
||||
既然是通用计算,既然是算一个 hash 值,那么民用级 CPU 和 GPU,浏览器或任何沙盒,虚拟机,移动设备当然就都可以。在我们的例子中,计算过程被做成分布式,每个用户可以各自计算,结果按 chunk 发回 master 汇总。这样就实现了终端用户 - 浏览器 - 共同贡献计算资源 - 换为 XMR 的过程。
|
||||
|
||||
这就是对整个链路的一个描述。从中我们会生出一些疑问,比如:
|
||||
|
||||
> 给我看看具体算什么 hash?为什么要算 XMR 而不是比特币或者其他?既然第一个算出的赢家通吃所有,为什么我的收益却是线性的?这种描述来看岂不是算力最大的一方**永远**都能算出结果而其他人颗粒无收吗?
|
||||
|
||||
要看具体算法,没有问题。bitcoin 在[这里](http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html),XMR 则看[CryptoNote Standard 008](https://cryptonote.org/cns/cns008.txt)
|
||||
|
||||
读完两个算法我们就有了以上疑问的答案:
|
||||
|
||||
### 2.1.1 为什么要算 XMR 而不是比特币或者其他
|
||||
XMR 不是唯一选择,但是 BTC 是一个不可选的选择。因为 double SHA-265 在专业级 GPU 上会比 CPU 上快 10^4 倍 ([更多信息](https://en.bitcoin.it/wiki/Why_a_GPU_mines_faster_than_a_CPU))。这样一百万用户合力浏览器挖矿还不如一架子双路 Titan,就失去了分布到终端用户的意义。而 CryptoNight 在 GPU 上只比同价值 CPU 快 2 倍。另外 CryptoNight 算法也被设计为不适用[ASIC](https://en.wikipedia.org/wiki/Application-specific_integrated_circuit)。
|
||||
|
||||
怎么实现的?CryptoNight 算法开宗明义地写明,运算主体是 Memory-Hard Loop,而不是 Computation-Hard Loop。每个循环都要在内存中检索。实际运行 CryptoNight 时,CPU 都会用最快,最接近 ALU 也是容量最小的 L3 Cache。换到 GPU,显存虽然很大,却没有 L3 Cache 一样的极致读写速度优化,而且由于内存读写成了瓶颈,GPU 中的大量 ALU 也没了用武之地。下图简略地描述了 CryptoNight 循环体的结构:
|
||||
|
||||

|
||||
|
||||
### 2.1.2 算力最大的一方永远都能算出结果
|
||||
看了比特币具体算法,你应该明白了 hash 是靠不停改变 nonce 来生成的。随机取一个值,算了不对,再随机取另一个 nonce 值..。既然是随机取,就不会存在赢家恒赢.
|
||||
|
||||
### 2.1.3 为什么我的收益却是线性的
|
||||
这是一个隐蔽但是却非常重要的问题。答案是,本来确实是赢家通吃。如果你的算力足够大,挖矿时间足够长之后总会轮到你,但是收益会有大幅波动.
|
||||
|
||||
就是因为如此,矿工们逐渐建立了矿池组织。大家把算力都投入到一起,合力算,然后不管这次实际是谁算出来,都按照贡献的算力比例分配收益。矿池是一个加密货币建立之初,完全推崇去中心化时没有预料到的结构,也产生了深远的影响。现在来自中国矿池的算力早已超过网络 50%,他们会在挖出的块中打上矿池标记,而这些矿池在加密货币的分叉,路线图中也扮演举足轻重的角色.
|
||||
|
||||
所以你的算力并不是直接投入 XMR 网络中,而是投入一个矿池。在我们的例子里矿池就是 coinhive,只不过是一个比较特殊的矿池,特殊在矿池成员都运作在浏览器中。这就是为什么你会得到线性收益而不是 all or none.
|
||||
|
||||
自古以来各行业都会自发产生行业工会,建立类似保险和行业守则 / 规范这些人人为我我为人人的机制。在 crypto 行业也不例外。这是意料之外而情理之中.
|
||||
|
||||
## 2.2 在浏览器里发生了什么,或 coinhive 干了什么
|
||||
好,我们搞清了一些基本的 Monero 挖矿机制,下面来看看 coinhive。已经知道 coinhive 帮我们接入它的矿池,让再小的算力也能按比例得到产出。但是还有什么呢?最关键的一点,coinhive 是怎样把一个完整的 mining 过程拆分成小块,让一个或许并不强大的设备上的浏览器,也能快速接收 task,快速完成并且即时上传的呢?
|
||||
|
||||
废话不多说,打开源码。本项目没有开源,构建完成后的在https://coinhive.com/lib/coinhive.min.js。先做初步 format 处理,发现有些工作完成在后端,worker shard 一侧。以下用松散的伪码总结一下 client side 的[main success scenario](https://wiki.ihris.org/wiki/Understanding_Use_Cases)流程 (注意很多地方简化了):
|
||||
|
||||
```plain
|
||||
- start
|
||||
- loadWorkerResource
|
||||
- load worker-asmjs.min.js
|
||||
- CRYPTONIGHT_WORKER_BLOB = createObjectURL(Blob(response_of_worker-asmjs.min.js))
|
||||
- _startNow -> _connectAfterSelfTest
|
||||
- selfTest -> verify(testJob),
|
||||
testJob = {
|
||||
verify_id: "1",
|
||||
nonce: "204f150c",
|
||||
result: "6a9c7dea83b079ce0e012907dd6929bcb0aeec3c1f06c032ca7c3386432bca00",
|
||||
blob: "0606c6d8cfd005cad45b0306350a730b0354d52f1b6d671063824287ce4a82c971d109d56d1f1b00000000ee2d1d4fd7c18bdc1b24abb902ac8ecc3d201ffb5904de9e476a7bbb0f9ec1ab04"
|
||||
};
|
||||
verify = if (!this._isReady) {
|
||||
this.verifyJob = job
|
||||
} else {
|
||||
this.worker.postMessage(job)
|
||||
}
|
||||
// 实例化若干个JobThread,每个对应一个worker,worker实际执行asmjs.min.js
|
||||
- _connect // verify成功,终于建立连接。根据public key固定hash到一个shard池然后随机选一个shard,建立websocket
|
||||
- websocket.onmessage: if (type==job) work()
|
||||
- work:
|
||||
do { hash(input,output) } while !(meetTarget(output));
|
||||
websocket.postMessage({nonce,output}) // hash done successfully。submit
|
||||
```
|
||||
|
||||
看一下这个过程,结合[cns003 XMR blockchain specs](https://cryptonote.org/cns/cns003.txt)。XMR 的整体 hash input 很小,是:
|
||||
```plain
|
||||
- size of [block_header,Merkle root hash,and the number of
|
||||
transactions] in bytes (varint)
|
||||
- block_header,
|
||||
- Merkle root hash,
|
||||
- number of transactions (varint).
|
||||
```
|
||||
|
||||
这样用 websocket 发过来毫无问题。之后就是完全独立的计算,调整 nonce 来算不同的 hash 结果。target 就是当前难度的一个指示.
|
||||
|
||||
这样整条链路就比较清晰了。再思考一下以下问题:
|
||||
|
||||
### 2.2.1 为什么 XMR 适宜分布式客户端计算
|
||||
因为能够利用每个用户的 CPU 和其中的**高速 L3 Cache**。这是中心化执行难以具备的条件.
|
||||
|
||||
任何时候当考虑要不要把某项操作推到客户端进行时,都要想明白可以利用客户端的哪个资源,这个资源在客户端是否有明显优势,是否比后端中心化执行更有利。**很多时候答案是,优势并不明显。那么引入的网络通信成本,法规成本,额外开销可能就并不值得.**
|
||||
|
||||
## 2.3 最后的步骤
|
||||
到了这里,最后剩余步骤就很标准模式化了。coinhive 作为矿场,代管着用户生产的加密货币。用户发请求提出 XMR,就需要提到一个自己的钱包地址保管,比如 [MyMonero](https://mymonero.com)。也可以直接提到 Exchange 交易所,在其中交易成其他币种,包括法币,然后电汇等等形式提现.
|
||||
|
||||
如果对钱包或者交易所感兴趣 (这两个也是很大的话题,比如钱包分硬件钱包和软件钱包,离线冷钱包和线上热钱包,private key 和 recover seeds。交易所有多种多样的交易对,有杠杆,期货,空和多,多种挂单类型等等),可以看[这里](https://www.blockchain-council.org/cryptocurrency/hot-wallet-vs-cold-wallet/)和[这里](https://github.com/txbits/txbits).
|
||||
|
||||
# 3 更多讨论
|
||||
|
||||
> 讨论地址是:[精读《全链路体验浏览器挖矿》 · Issue #55 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/55)
|
||||
|
||||
**如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周五发布。**
|
||||
|
||||
# 4 延伸阅读
|
||||
http://piotrpasich.com/introduction-bitcoin-for-developers
|
||||
|
||||
https://en.wikipedia.org/wiki/Monero_(cryptocurrency)
|
||||
|
||||
http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html
|
||||
|
||||
https://cryptonote.org/cns/cns001.txt
|
||||
cns001-008 是 Specs 集合
|
||||
|
||||
https://en.bitcoin.it/wiki/Why_a_GPU_mines_faster_than_a_CPU
|
||||
|
||||
https://en.wikipedia.org/wiki/Application-specific_integrated_circuit
|
||||
|
||||
https://github.com/txbits/txbits
|
||||
@@ -2,7 +2,7 @@
|
||||
## 引言
|
||||
2018 年初,蚂蚁金服 See Conf 上第一个分享《Ant Design 3.0 背后的故事》给很多人带来了启发。主题精彩又深刻,值得反复咀嚼。
|
||||
|
||||
## 内容概要
|
||||
## 内容概要
|
||||
### 设计体系
|
||||
Atomic Design 书中提到模块化思路以及原子级的模块抽象的方法启发了很多设计师。而解读者中较为说法较作者认同。设计体系是一个具包容性且充满生命力的东西。包容性指的是从组件库到设计语言到设计方法等所有和产品设计相关的方面。而生命力指的是它并非静态的内容,而是可以应对不断变化的环境,是一个不断进化的过程。
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# 增强现实与可视化
|
||||
## 引言
|
||||
增强现实,Augmented Reality,简称AR。在VR的热潮已经褪去,AI当下正红的技术圈里,AR似乎已经成为了过气网红。但似乎在现在,我们可以来冷静地看待一下增强现实这个概念。
|
||||
增强现实,Augmented Reality,简称 AR。在 VR 的热潮已经褪去,AI 当下正红的技术圈里,AR 似乎已经成为了过气网红。但似乎在现在,我们可以来冷静地看待一下增强现实这个概念。
|
||||
|
||||
做前端的最终还是要和用户打交道的,增强现实是不是为用户界面带来了新的可能?可视化作为前端的一个细分领域,这篇文章正是从这个角度出发来重新认识增强现实与可视化。
|
||||
|
||||
## 内容概要
|
||||
|
||||
移动设备为我们带来了巨大的便利,但是在各种好处下,有一点不容忽视:屏幕太小,根本没有更多的空间来放置更多的内容。对于数据可视化而言,更大的空间意味着更好的数据分析能力。而在空间这件事情上,AR正是很好地解决了这个问题。当下,AR的主要形态还是将虚拟信息作为图层叠加在现实图像之上的形态,这样的AR其实更接近于混合现实。例如使用面部追踪给你脸上加上小动物的Snapchat Lenses,可以在沙发茶几上玩MineCraft的微软HoloLens,和苹果最近新出的ARKit都是这种。
|
||||
移动设备为我们带来了巨大的便利,但是在各种好处下,有一点不容忽视:屏幕太小,根本没有更多的空间来放置更多的内容。对于数据可视化而言,更大的空间意味着更好的数据分析能力。而在空间这件事情上,AR 正是很好地解决了这个问题。当下,AR 的主要形态还是将虚拟信息作为图层叠加在现实图像之上的形态,这样的 AR 其实更接近于混合现实。例如使用面部追踪给你脸上加上小动物的 Snapchat Lenses,可以在沙发茶几上玩 MineCraft 的微软 HoloLens,和苹果最近新出的 ARKit 都是这种。
|
||||
|
||||
所以要怎么通过增强现实来解决当下移动端屏幕空间不足的问题呢?在AR的概念下,一切皆屏幕,现实之上的任何地方都可以展示信息。对于增强现实的未来,文章给出了3个可能的方向。首先,需要提供更好的针对个人的视觉体验。其次,要更好地利用3D展示。最后,让屏幕悬浮在任何地方。
|
||||
所以要怎么通过增强现实来解决当下移动端屏幕空间不足的问题呢?在 AR 的概念下,一切皆屏幕,现实之上的任何地方都可以展示信息。对于增强现实的未来,文章给出了 3 个可能的方向。首先,需要提供更好的针对个人的视觉体验。其次,要更好地利用 3D 展示。最后,让屏幕悬浮在任何地方。
|
||||
|
||||
但是我们也不妨从反面重新理性地看到了增强现实。是不是有了足够空间展示东西我们就要把东西一股脑都展示出来呢?并不是的,增强现实是和真实世界的混合。所以增强现实下的可视化,也不是也不是简单地照搬网页。在增强现实下,我们所展示的每一个虚拟物体,是需要有现实依据的。但是也不必拘泥于现实,增强现实也可以改造所展示的世界。增强现实并不是简单的做加法,只能构建出各类虚拟物品叠加在世界上。同样也能改造世界,使事物变形和消失。
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
前端是什么?对于这样一个本源性的话题。每个人都有自己不同的理解。我也不会说书式得非得确定这个问题的答案。但是可以确定的是,如果一切的描述要带上设备端的前提,是短视的。
|
||||
|
||||
从PC Web到移动App,前端并没有消失,各大网站也都纷纷开始将自己的网站搬到了手机上以移动APP的形式存在。同样的,如果有一天增强现实来到我们的生活。前端作为和用户界面直接接触的工作,毫无疑问已经会是很重要的一部分。
|
||||
从 PC Web 到移动 App,前端并没有消失,各大网站也都纷纷开始将自己的网站搬到了手机上以移动 APP 的形式存在。同样的,如果有一天增强现实来到我们的生活。前端作为和用户界面直接接触的工作,毫无疑问已经会是很重要的一部分。
|
||||
|
||||
再看可视化。移动化的大潮让我们开始习惯移动设备,触屏之类的交互的确让我们的信息获取变得更加方便。但是这并不代表全部,特殊行业的人依旧离不开传统的PC,尤其是数据分析人员,对于他们而言,更大的屏幕等于一切。尤其是金融分析师,你给他们四块屏幕都不够用。增强现实下的可视化的确是对这些人的一个重要利好。原因无非就是增强现实的可展现区域相当于整个人眼的视角,远远大于任何我们可以感知到的屏幕。
|
||||
再看可视化。移动化的大潮让我们开始习惯移动设备,触屏之类的交互的确让我们的信息获取变得更加方便。但是这并不代表全部,特殊行业的人依旧离不开传统的 PC,尤其是数据分析人员,对于他们而言,更大的屏幕等于一切。尤其是金融分析师,你给他们四块屏幕都不够用。增强现实下的可视化的确是对这些人的一个重要利好。原因无非就是增强现实的可展现区域相当于整个人眼的视角,远远大于任何我们可以感知到的屏幕。
|
||||
|
||||
如果只是在我们的眼睛上盖上一层信息,那是远远不够的,这样的增强现实仅仅是对屏幕的扩展。增强现实最关键的一点是和现实世界的充分结合:例如配合地理信息和我们的地理定位所带来的信息可视化展示;通过图像识别对物体的感知后,在物体上进行信息可视化展示;等等。文章的几个建议中,最后一个特别有趣——让屏幕悬浮在任何地方。这有两层含义,一是要充分利用好上面所提到的增强现实下的空间,二是我们需要清楚地认识到,人类对于二维世界的感知能力还是远远超出三维世界的。过度利用现实世界所构建出的3D场景,可能并不能为我们的分析带来太多进步。所以,二维的图形信息展示可能依然是增强现实可视化中很重要的一部分。
|
||||
如果只是在我们的眼睛上盖上一层信息,那是远远不够的,这样的增强现实仅仅是对屏幕的扩展。增强现实最关键的一点是和现实世界的充分结合:例如配合地理信息和我们的地理定位所带来的信息可视化展示;通过图像识别对物体的感知后,在物体上进行信息可视化展示;等等。文章的几个建议中,最后一个特别有趣——让屏幕悬浮在任何地方。这有两层含义,一是要充分利用好上面所提到的增强现实下的空间,二是我们需要清楚地认识到,人类对于二维世界的感知能力还是远远超出三维世界的。过度利用现实世界所构建出的 3D 场景,可能并不能为我们的分析带来太多进步。所以,二维的图形信息展示可能依然是增强现实可视化中很重要的一部分。
|
||||
|
||||
这篇文章更加引起我兴趣的地方在于它对于可视化基本元素进行了分析——颜色,亮度,纹理,尺寸,方向、形状、位置……这些从我们平时的显示器屏幕或者手机屏幕上所展示的可视化元素会带来完全不一样的表现。增强现实的增强在于我们可以对现实的展示进行改造,纹理是很有趣的一块。一般来说我们平时做可视化分析,常用到阴影,虚线这些纹理,但是现实世界里的纹理就太丰富了,我们可以充分利用现实花纹了,让展现更直观更融合。
|
||||
|
||||
@@ -48,7 +48,7 @@ Rekit Studio 以逻辑视图重新组织了项目,文件目录不见了,取
|
||||
|
||||
同时支持在线管理本地文件、集成了 [https://microsoft.github.io/monaco-editor/](monaco-editor) 在线编辑文件,以及在线构建、测试等功能。
|
||||
|
||||
同时利用和弦图分析了路由与数据流之间绑定关系,路由与文件绑定关系,可以很轻松找到被遗弃的孤立节点。项目维护时,以看图代替看代码,效率至少提升2 3倍。
|
||||
同时利用和弦图分析了路由与数据流之间绑定关系,路由与文件绑定关系,可以很轻松找到被遗弃的孤立节点。项目维护时,以看图代替看代码,效率至少提升 2 3 倍。
|
||||
|
||||
### Cli 与可视化等效
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# 精读《快速上手构建 ARKit 应用》
|
||||
|
||||
原文地址: [how-to-make-your-own-arkit-app-in-5-minutes-using-react-native](https://medium.com/@HippoAR/how-to-make-your-own-arkit-app-in-5-minutes-using-react-native-9d7ce109a4c2)
|
||||
|
||||
## 引言
|
||||
ARKit 是苹果推出的增强现实套装,而 react-native-arkit 是基于此的上层封装。对于前端开发而言,这可能是最快上手 ARKit 的方式了,本周精读让我们来初窥 ARKit 和 React Native ARKit 这个库。
|
||||
|
||||
## 概要
|
||||
本次精读我们带来的是一篇《快速上手构建 ARKit 应用》,原文链接如上。原文标题更加直接,直译的话是“如何在 5 分钟里利用 react native 搭建出你自己的 ARKit 应用”。确实,这篇文章整体也非常明确,以跑起整个 ARKit Demo 为最直接最主要的目的。
|
||||
|
||||
跑起 ARKit,也很简单。硬件上,只要有一台 iPhone 6S 以上的手机;软件上,只要准备好最新版本的 XCode 和日常开发要用的 Node 环境了就好。按照`react-native-arkit`的里面的 README 就可以跑起来了。这个库不
|
||||
|
||||
## 3 精读
|
||||
在开始精读前,我先抛出我的问题三连:Why AR? Why ARKit? Why React Native ARKit?
|
||||
|
||||
### 3.1 Why AR?
|
||||
在之前的第 43 期精读评论中,我们探讨了 AR 对于和前端结合的可能性。总的来说,AR 把前端开发不再局限在有限的屏幕空间上,对于可视化等对前端展示空间有强烈需求的细分领域,AR 是一个很值得研究的内容。如果对于这一块内容有兴趣,欢迎回看第 43 期精读评论 [《精读〈增强现实与可视化〉》](https://github.com/dt-fe/weekly/blob/master/43.%E7%B2%BE%E8%AF%BB%E3%80%8A%E5%A2%9E%E5%BC%BA%E7%8E%B0%E5%AE%9E%E4%B8%8E%E5%8F%AF%E8%A7%86%E5%8C%96%E3%80%8B.md)。
|
||||
|
||||
### 3.2 Why ARKit?
|
||||
为什么选择 ARKit 入手进行实验?其因有二。第一,相比于 Microsoft HoloLens 的价格,售价只有它三分之一的 iPhone X 无论是体积重量,还是性价比,抑或是保有量都是大大占优的。噢对,说到保有量,iPhone 6S 及以上都支持 ARKit。所以说 iPhone 是我们身边最容易接触到的 AR 设备是不为过的。第二,ARKit 对于硬件的利用能力非一般的前端库可以做到的。大部分的 AR 前端库可以做到利用陀螺仪来构建一个三维立体空间。但是 ARKit 更进一步,他利用高频调用摄像头,通过对图像进行识别分析,可以进行空间感知,例如可以识别出一个平面。而这些都是 ARKit 所提供的,我们只需要调用它的能力就好了。对于开发者而言,ARKit 会比一般的 AR 库更近一步。
|
||||
|
||||
### 3.3 Why React Native ARKit?
|
||||
对于当下的前端开发,所有事情可以分为两种——0. 可以用 JavaScript 写的 1. 其他。至于为什么选择`react-native-arkit`这个库,原因自然也可以理解。相比于用原生的 Swift 来开发,React Native 的开发方式对于前端而言明显是更加容易上手了。对于尝试新东西,这也未尝不可。
|
||||
|
||||
### 3.4 About Demo
|
||||
相比于原文中从初始化开始的步骤,官方还提供了一个已经配置好的[官方 Demo](https://github.com/HippoAR/ReactNativeARKit)。使用这个,如果环境没有问题,的确只需要 5 分钟就可以跑起来一个 ARKit 应用了。
|
||||
|
||||

|
||||
|
||||
上面的图片来自原文,可以看到,在`react-native-arkit`这个库里面的所支持的 9 种基本图形和文字。使用如下已经封装好的 React Native 组件就可以直接使用了。
|
||||
|
||||
```javasctipt
|
||||
<ARKit.Box
|
||||
pos={{ x: 0, y: 0, z: 0 }}
|
||||
shape={{ width: 0.1, height: 0.1, length: 0.1, chamfer: 0.01 }}
|
||||
/>
|
||||
```
|
||||
|
||||
[几何构造](http://v.youku.com/v_show/id_XMzUxMjk3NjUxMg==.html)
|
||||
上面的一个视频片段是我们在跑起来 Demo 后的立体效果。可以很清楚地看到,ARKit 感知到了房间这个立方体空间后所构建出来的 AR 的效果。
|
||||
|
||||
[平面识别](http://v.youku.com/v_show/id_XMzUxMjk3OTc0NA==.html)
|
||||
而最后的这段视频会更加有趣一些,中央的红圈的出现逻辑是停留在最近识别出的一个平面上。我们可以看到首先识别出了地面,红圈随地面而动;再移向桌面时,很快又识别出了桌面,重新生成了一个停留在桌面上的红圈。通过这一段可以看出无论是明暗划分明显的地面,还是堆满杂物的桌面,ARKit 都可以很轻松的识别出来。
|
||||
|
||||
## 4. 总结
|
||||
苹果的 ARKit 对空间平面的感知能力胜过了一般的 AR 渲染库。而 iPhone 6S 就能跑的特性又让我们觉得 AR 其实并没有那么遥远。在此基础之上的 React Native 封装`react-native-arkit`,让我们通过 JS 就拥有操作 ARKit 的能力。这的确是一个快速上手 ARKit 的方式。
|
||||
|
||||
|
||||
## 5 更多讨论
|
||||
讨论地址是:[精读《快速上手构建 ARKit 应用》 · Issue #70 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/70)
|
||||
|
||||
如果你想参与讨论,请[点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,每周末发布。
|
||||
@@ -1,10 +1,10 @@
|
||||
# 1 引言
|
||||
|
||||
本周精读, 来一起总结web开发的环节, 知识块和技能点. 是不是像xx速成班宣传的一样, 培训三个月, 经验顶三年, 入职BAT, 年薪三十万?
|
||||
本周精读, 来一起总结 web 开发的环节, 知识块和技能点. 是不是像 xx 速成班宣传的一样, 培训三个月, 经验顶三年, 入职 BAT, 年薪三十万?
|
||||
|
||||
本文虽然是罗列知识点, 但我想很有意义. 对于学习的人来说, 提供一个路线图. 对从业者来说, 对全局有更好的把控, 利于看到自己的强项和不足. 对组建团队, 更能起到一个点将谱的作用.
|
||||
|
||||
在网上我没有搜到任何深入全面的总结, 提供的那几篇已经算稍微好一些的了. 其他的要么太过笼统(前端-后端-数据-运维, 完毕)要么太细太窄(并不是不好, 只是和本文性质不一样). Generalist和Specialist之间永远是一对辩证矛盾, 持续思考.
|
||||
在网上我没有搜到任何深入全面的总结, 提供的那几篇已经算稍微好一些的了. 其他的要么太过笼统(前端-后端-数据-运维, 完毕)要么太细太窄(并不是不好, 只是和本文性质不一样). Generalist 和 Specialist 之间永远是一对辩证矛盾, 持续思考.
|
||||
|
||||
本文提供了有层级的列表形式, 如果有兴趣的读者可以把它做成概念图形式, 相互关联与距离相关, 可能会有意料之外的效果.
|
||||
|
||||
@@ -94,9 +94,9 @@ CJS 的做法很不同,主要是由于相对于通过网络请求从文件系
|
||||
|
||||

|
||||
|
||||
在浏览器中你只要将 `type="module" ` 放在 script 标签上。这会通知浏览器这个文件应该被转化为一个模块。同样,只有模块才能够被导入,浏览器也就知道了模块中有哪些引用。
|
||||
在浏览器中你只要将 `type="module"` 放在 script 标签上。这会通知浏览器这个文件应该被转化为一个模块。同样,只有模块才能够被导入,浏览器也就知道了模块中有哪些引用。
|
||||
|
||||
不过在 Node 中,并没有 HTML 标签,所以也没有地方声明 type 属性。社区内的一种方式就是使用 `.mjs` 扩展。使用这个扩展告诉 Node这个文件是一个模块。
|
||||
不过在 Node 中,并没有 HTML 标签,所以也没有地方声明 type 属性。社区内的一种方式就是使用 `.mjs` 扩展。使用这个扩展告诉 Node 这个文件是一个模块。
|
||||
|
||||
无论哪种方式,加载器将决定是否将文件转化为一个模块。如果是一个模块并且有导入的话,它就会开始处理直到所有的文件被获取和转化。
|
||||
|
||||
@@ -94,7 +94,7 @@ const incrementAsync = async count => {
|
||||
|
||||
### 将 action + reducer 改为两种 action
|
||||
|
||||
redux 抽象的 action 与 reducer 的指责很清晰,action 负责改 store 以外所有事,而 reducer 负责改 store,偶尔用来做数据处理。这种概念其实比较模糊,因为往往不清楚数据处理放在 action 还是 reducer 里,同时过于简单的 reducer 又要写 action 与之匹配,感觉过于形式化,而且繁琐。
|
||||
redux 抽象的 action 与 reducer 的职责很清晰,action 负责改 store 以外所有事,而 reducer 负责改 store,偶尔用来做数据处理。这种概念其实比较模糊,因为往往不清楚数据处理放在 action 还是 reducer 里,同时过于简单的 reducer 又要写 action 与之匹配,感觉过于形式化,而且繁琐。
|
||||
|
||||
重新考虑这个问题,我们只有两类 action:`reducer action` 与 `effect action`。
|
||||
|
||||
@@ -87,7 +87,7 @@ function getTokenBlockComment(restStr: string) {
|
||||
```typescript
|
||||
while (sqlStr) {
|
||||
token =
|
||||
getTokenWhitespace(sqlStr, token) | getTokenBlockComment(sqlStr, token);
|
||||
getTokenWhitespace(sqlStr, token) || getTokenBlockComment(sqlStr, token);
|
||||
|
||||
sqlStr = sqlStr.substring(token.value.length);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
我们将一块语法规则称为 **产生式**,使用 “Left → Right” 表示任意产生式,用 “Left => Right” 表示产生式的推导过程,比如对于产生式:
|
||||
|
||||
```
|
||||
```plain
|
||||
E → i
|
||||
E → E + E
|
||||
```
|
||||
@@ -17,7 +17,7 @@ E → E + E
|
||||
|
||||
举个例子,比如 `SELECT * FROM table` 可以被表达为:
|
||||
|
||||
```
|
||||
```plain
|
||||
S → SELECT * FROM table
|
||||
```
|
||||
|
||||
@@ -31,7 +31,7 @@ S → SELECT * FROM table
|
||||
|
||||
终结符就是语句的终结,读到它表示产生式分析结束,相反,非终结符就是一个新产生式的开始,比如:
|
||||
|
||||
```
|
||||
```plain
|
||||
<selectStatement> ::= SELECT <selectList> FROM <tableName>
|
||||
|
||||
<selectList> ::= <selectField> [ , <selectList> ]
|
||||
@@ -43,7 +43,7 @@ S → SELECT * FROM table
|
||||
|
||||
对于有二义性的文法,可以通过 **上下文相关文法** 方式描述,也就是在产生式左侧补全条件,解决二义性:
|
||||
|
||||
```
|
||||
```plain
|
||||
aBc -> a1c | a2c
|
||||
dBe -> d3e
|
||||
```
|
||||
@@ -52,7 +52,7 @@ dBe -> d3e
|
||||
|
||||
上面表示,非终结符 `B` 在 `ac` 之间时,可以解析为 `1` 或 `2`,而在 `de` 之间时,解析为 `3`。但我们可以增加一个非终结符让产生式可读性更好:
|
||||
|
||||
```
|
||||
```plain
|
||||
B -> 1 | 2
|
||||
C -> 3
|
||||
```
|
||||
@@ -86,7 +86,7 @@ SELECT * from bees WHERE bee = 'red';
|
||||
|
||||
上面提到的推导符号 `=>` 在实际运行过程中,显然有两种方向左和右:
|
||||
|
||||
```
|
||||
```plain
|
||||
E + E => ?
|
||||
```
|
||||
|
||||
@@ -100,7 +100,7 @@ E + E => ?
|
||||
|
||||
比如 `select <selectList>` 的 `selectList` 产生式,它可以表示为:
|
||||
|
||||
```
|
||||
```plain
|
||||
<SelectList> ::= <SelectList> , <SelectField>
|
||||
| <SelectField>
|
||||
```
|
||||
@@ -115,7 +115,7 @@ E + E => ?
|
||||
|
||||
> Token 见上一期精读 [精读《手写 SQL 编译器 - 词法分析》](https://github.com/dt-fe/weekly/blob/master/64.%E7%B2%BE%E8%AF%BB%E3%80%8A%E6%89%8B%E5%86%99%20SQL%20%E7%BC%96%E8%AF%91%E5%99%A8%20-%20%E8%AF%8D%E6%B3%95%E5%88%86%E6%9E%90%E3%80%8B.md)
|
||||
|
||||
```
|
||||
```plain
|
||||
<SelectList> ::= <SelectField> <G>
|
||||
|
||||
<G> ::= , <SelectList>
|
||||
@@ -124,12 +124,12 @@ E + E => ?
|
||||
|
||||
这其实是一个通用处理,可以抽象出来:
|
||||
|
||||
```
|
||||
```plain
|
||||
E → E + F
|
||||
E → F
|
||||
```
|
||||
|
||||
```
|
||||
```plain
|
||||
E → FG
|
||||
G → + FG
|
||||
G → null
|
||||
@@ -139,7 +139,7 @@ G → null
|
||||
|
||||
笔者建议此处不要生硬的套公式,在套了公式后,再对产生式做一些修饰,让其更具有语义:
|
||||
|
||||
```
|
||||
```plain
|
||||
<SelectList> ::= <SelectField>
|
||||
| , <SelectList>
|
||||
```
|
||||
@@ -152,7 +152,7 @@ G → null
|
||||
|
||||
设想如下的 sql 文法:
|
||||
|
||||
```
|
||||
```plain
|
||||
<Field> ::= <Text> as <Text>
|
||||
| <Text> as<String>
|
||||
| <Text> <Text>
|
||||
@@ -161,7 +161,7 @@ G → null
|
||||
|
||||
其实 Text 本身也是比较复杂的产生式,最坏的情况需要对 Text 连续匹配六遍。我们将 Text 公因式提取出来就可以仅匹配一遍,因为无论是何种 Field 产生式,都必定先遇到 Text:
|
||||
|
||||
```
|
||||
```plain
|
||||
<Field> ::= <Text> <F>
|
||||
|
||||
<F> ::= <G>
|
||||
@@ -131,7 +131,7 @@ const selectList =
|
||||
|
||||
显然这样做不具备通用性,因为我们将参数名与数量固定了。考虑到上期精读学到的[文法](https://github.com/dt-fe/weekly/blob/master/65.%E7%B2%BE%E8%AF%BB%E3%80%8A%E6%89%8B%E5%86%99%20SQL%20%E7%BC%96%E8%AF%91%E5%99%A8%20-%20%E6%96%87%E6%B3%95%E4%BB%8B%E7%BB%8D%E3%80%8B.md),我们可以这样描述 `selectList`:
|
||||
|
||||
```
|
||||
```plain
|
||||
selectList ::= word (',' selectList)?
|
||||
word ::= [a-zA-Z]
|
||||
```
|
||||
@@ -183,7 +183,7 @@ const field = () => word()
|
||||
|
||||
这时注意 `field` 作为一个字段,也可能是文本或函数,我们假设拥有函数处理函数 `functional`,那么用文法描述 `field` 就是:
|
||||
|
||||
```
|
||||
```plain
|
||||
field ::= text | functional
|
||||
```
|
||||
|
||||
@@ -228,7 +228,7 @@ function tree(...args: any[]) {
|
||||
|
||||
可选函数就是分支函数的一个特例,可以描述为:
|
||||
|
||||
```
|
||||
```plain
|
||||
func? => func | ε
|
||||
```
|
||||
|
||||
@@ -244,25 +244,25 @@ const optional = fn => tree(fn, () => true)
|
||||
|
||||
上面通过对 SQL 语句的实践,发现了 `match` 匹配单个单词、 `&&` 连接、`tree` 分支、`ε` 空字符串的产生式这四种基本用法,这是符合下面四个基本文法组合思想的:
|
||||
|
||||
```
|
||||
```plain
|
||||
G ::= ε
|
||||
```
|
||||
|
||||
空字符串产生式,对应 `() => true`,不消耗 Token,总是返回 `true`。
|
||||
|
||||
```
|
||||
```plain
|
||||
G ::= t
|
||||
```
|
||||
|
||||
单词匹配,对应 `match(t)`。
|
||||
|
||||
```
|
||||
```plain
|
||||
G ::= x y
|
||||
```
|
||||
|
||||
连接运算,对应 `match(x) && match(y)`。
|
||||
|
||||
```
|
||||
```plain
|
||||
G ::= x
|
||||
G ::= y
|
||||
```
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
为了更加详细的描述这个问题,举一个例子,存在以下岔路:
|
||||
|
||||
```
|
||||
```plain
|
||||
a -> tree() -> c
|
||||
-> b1 -> b1'
|
||||
-> b2 -> b2'
|
||||
@@ -174,7 +174,7 @@ ChainNode 是对链表节点的定义,这里给出了和当前文章内容相
|
||||
|
||||
整个链表结构可能是这样的:
|
||||
|
||||
```
|
||||
```plain
|
||||
node1 <-> node2 <-> node3 <-> node4
|
||||
|- function2-1
|
||||
|- matchToken2-1
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<img src="assets/68/2.jpg" />
|
||||
|
||||
产品用户体验不仅是指交互视觉,我的理解用户体验反应用户与产品从认知,使用到传播整个情感的连接和反馈。能力上包括了产品设计与功能实现,用户交互界面,以及系统承载能力。
|
||||
产品用户体验不仅是指交互视觉,我的理解用户体验反映用户与产品从认知,使用到传播整个情感的连接和反馈。能力上包括了产品设计与功能实现,用户交互界面,以及系统承载能力。
|
||||
|
||||
上图是 CUBI Mobel:CUBI UX - User Experience Model。完整地说明了用户体验从内容、商业目标、交互、用户目标四个方面组合。
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
我试着列了几类
|
||||
|
||||
1. 产品商业阶段性目标和最终目标。营收提高,优化结构,工程效率提高,质量提高,能力覆盖。
|
||||
2. 工程研发过程及能力。投入产出比,系统成本,系统稳定性,创新性?。
|
||||
2. 工程研发过程及能力。投入产出比,系统成本,系统稳定性,创新性。
|
||||
3. 用户可用性。满意度,过程效率,过程质量。
|
||||
|
||||
## 总结
|
||||
@@ -249,7 +249,7 @@ const App = epitath(function*() {
|
||||
|
||||
通过 immutagen,依次调用 `next`,生成新组件,且下一个组件是上一个组件的子组件,因此会产生下面的效果:
|
||||
|
||||
```
|
||||
```plain
|
||||
yield <A>
|
||||
yield <B>
|
||||
yield <C>
|
||||
@@ -49,7 +49,7 @@ runPromiseByQueue([
|
||||
|
||||
得到的输出是:
|
||||
|
||||
```
|
||||
```plain
|
||||
promise 1
|
||||
promise 2
|
||||
promise 3
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
重回 “手写 SQL 编辑器” 系列。这次介绍如何利用缓存优化编译器执行性能。
|
||||
|
||||
可以利用 **Frist 集** 与 **Match 节点缓存** 这两种方式优化。
|
||||
可以利用 **First 集** 与 **Match 节点缓存** 这两种方式优化。
|
||||
|
||||
本文会用到一些图做解释,下面介绍图形规则:
|
||||
|
||||
@@ -44,7 +44,7 @@ Match 节点缓存,指在运行时,缓存节点到其第一个终结符的
|
||||
|
||||
拿 `select a, b, c, d from e` 这个语句做测试:
|
||||
|
||||
| node 节点访问次数 | Frist 集优化 | First 集 + Match 节点缓存优化 |
|
||||
| node 节点访问次数 | First 集优化 | First 集 + Match 节点缓存优化 |
|
||||
| ----------------- | ------------ | ----------------------------- |
|
||||
| 784 | 669 | 652 |
|
||||
|
||||
@@ -214,7 +214,7 @@ class Component extends React.PureComponent<Props, State> {
|
||||
this.rootDom = ReactDOM.findDOMNode(this.rootDomRef) as HTMLDivElement;
|
||||
|
||||
this.chart = new G2.Chart({
|
||||
container: document.getElementById("chart"),
|
||||
container: this.rootDom,
|
||||
forceFit: true,
|
||||
height: 300
|
||||
});
|
||||
@@ -259,7 +259,7 @@ const { loading, error, result } = useAsync(fetchUser, [id]);
|
||||
实现:在 Promise 的初期设置 loading,结束后设置 result,如果出错则设置 error,这里可以将请求对象包装成 `useAsyncState` 来处理,这里就不放出来了。
|
||||
|
||||
```tsx
|
||||
export function useAsync(asyncFunction) {
|
||||
export function useAsync(asyncFunction: any, params: any[]) {
|
||||
const asyncState = useAsyncState(options);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -326,8 +326,8 @@ const fetchUser = id =>
|
||||
});
|
||||
|
||||
function useFetchUser(id) {
|
||||
const asyncFetchUser = useAsync(fetchUser, id);
|
||||
return asyncUser;
|
||||
const asyncFetchUser = useAsync(fetchUser, [id]);
|
||||
return asyncFetchUser;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -499,12 +499,23 @@ useEffect(() => {
|
||||
const update = useUpdate();
|
||||
```
|
||||
|
||||
实现:我们知道 `useState` 下标为 1 的项是用来更新数据的,而且就算数据没有变化,调用了也会刷新组件,所以我们可以把返回一个没有修改数值的 `setValue`,这样它的功能就仅剩下刷新组件了。
|
||||
实现:我们知道 `useState` 下标为 1 的项是用来更新数据的,但数据必须有变化才会触发 render,因此我们可以这样设计:
|
||||
|
||||
```tsx
|
||||
const useUpdate = () => useState(0)[1];
|
||||
const useUpdate = () => {
|
||||
const [, setState] = useState(0);
|
||||
return () => setState(cnt => cnt + 1);
|
||||
};
|
||||
```
|
||||
|
||||
或者利用 `useReducer` 做一个简单的 Action 来支持:
|
||||
|
||||
```tsx
|
||||
const [, forceRender] = useReducer(s => s + 1, 0);
|
||||
```
|
||||
|
||||
> 感谢:感谢用户 [cike8899](https://github.com/cike8899) 对此处的勘误,并提供示例代码。
|
||||
|
||||
> 对于 `getSnapshotBeforeUpdate`, `getDerivedStateFromError`, `componentDidCatch` 目前 Hooks 是无法模拟的。
|
||||
|
||||
#### isMounted
|
||||
@@ -31,7 +31,7 @@ html`
|
||||
`;
|
||||
```
|
||||
|
||||
很显然,由于跳过了 JSX 编译,换成了原生的 [Template Strings ](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings) ,所以所有组件、属性部分都需要改成 `${}` 语法,比如:
|
||||
很显然,由于跳过了 JSX 编译,换成了原生的 [Template Strings](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings) ,所以所有组件、属性部分都需要改成 `${}` 语法,比如:
|
||||
|
||||
`<${Header}>` 这种写法略显别扭,但整体上还是蛮直观的。
|
||||
|
||||
@@ -57,7 +57,7 @@ interface VDom {
|
||||
props: {
|
||||
[attrKey: string]: string;
|
||||
};
|
||||
chindren: VDom[];
|
||||
children: VDom[];
|
||||
}
|
||||
```
|
||||
|
||||
@@ -149,9 +149,9 @@ Fiber 利用分片的思想,把一个耗时长的任务分成很多小片,
|
||||
因此,在组件更新时有可能一个更新任务还没有完成,就被另一个更高优先级的更新过程打断,优先级高的更新任务会优先处理完,而低优先级更新任务所做的工作则会完全作废,然后等待机会重头再来。所以 React Fiber 把一个更新过程分为两个阶段:
|
||||
|
||||
- 第一个阶段 Reconciliation Phase,Fiber 会找出需要更新的 DOM,这个阶段是可以被打断的;
|
||||
- 第二个阶段 Commit Phase,是无法别打断,完成 DOM 的更新并展示;
|
||||
- 第二个阶段 Commit Phase,是无法被打断的,完成 DOM 的更新并展示;
|
||||
|
||||
在使用 Fiber 后,需要要检查与第一阶段相关的生命周期函数,避免逻辑的多次或重复调用:
|
||||
在使用 Fiber 后,需要检查与第一阶段相关的生命周期函数,避免逻辑的多次或重复调用:
|
||||
|
||||
- componentWillMount
|
||||
- componentWillReceiveProps
|
||||
@@ -504,7 +504,7 @@ export default {
|
||||
|
||||
## 2.13. Field
|
||||
|
||||
与 Value 组件唯一的区别,就是
|
||||
与 Value 组件唯一的区别,就是支持了 `bind`。
|
||||
|
||||
### 用法
|
||||
|
||||
@@ -247,7 +247,7 @@ const functionC = () => chain("y", "c")();
|
||||
|
||||
我们就得到了如下的链表:
|
||||
|
||||
```
|
||||
```plain
|
||||
ChainNode(main)
|
||||
└── FunctionNode(functionA) ─ TreeNode ─ FunctionNode(functionC)
|
||||
│── FunctionNode(functionB1)
|
||||
@@ -163,7 +163,7 @@ export const backendMain = () => {
|
||||
|
||||
在文件夹视图下,可以做如下结构规划:
|
||||
|
||||
```
|
||||
```plain
|
||||
.
|
||||
├── client # 前端入口
|
||||
├── server # 后端入口
|
||||
@@ -422,7 +422,7 @@ function Article({ id }) {
|
||||
return () => {
|
||||
didCancel = true;
|
||||
};
|
||||
}, [fetchArticle]);
|
||||
}, [API.fetchArticle]);
|
||||
|
||||
// ...
|
||||
}
|
||||
@@ -101,8 +101,8 @@ function SearchResults({ query }) {
|
||||
const [data, setData] = useState(null);
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
|
||||
const fetchResults = useCallback(() => {
|
||||
return "http://myapi/results?query" + query + "&page=" + currentPage;
|
||||
const getFetchUrl = useCallback(() => {
|
||||
return "http://myapi/results?query=" + query + "&page=" + currentPage;
|
||||
}, [currentPage, query]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -114,7 +114,7 @@ function SearchResults({ query }) {
|
||||
}
|
||||
```
|
||||
|
||||
Function Component 对 `props` 与 `state` 的数据都一视同仁,且可以将取数逻辑与 “更新判断” 通过 `useCallback` 完全封装在一个函数内,再将这个函数作为整体依赖项添加到 `useEffect`,如果未来再新增一个参数,只要修改 `fetchResults` 这个函数即可,而且还可以通过 `eslint-plugin-react-hooks` 插件静态分析是否遗漏了依赖项。
|
||||
Function Component 对 `props` 与 `state` 的数据都一视同仁,且可以将取数逻辑与 “更新判断” 通过 `useCallback` 完全封装在一个函数内,再将这个函数作为整体依赖项添加到 `useEffect`,如果未来再新增一个参数,只要修改 `getFetchUrl` 这个函数即可,而且还可以通过 `eslint-plugin-react-hooks` 插件静态分析是否遗漏了依赖项。
|
||||
|
||||
Function Component 不但将依赖项聚合起来,还解决了 Class Component 分散在多处生命周期的函数判断,引发的无法静态分析依赖的问题。
|
||||
|
||||
@@ -292,7 +292,7 @@ ReactDOM.render(
|
||||
|
||||
根据笔者的经验,**从上层业务到底层通用组件之间,本地状态数量是递增的:**
|
||||
|
||||
```
|
||||
```plain
|
||||
业务
|
||||
-> 全局数据流
|
||||
-> 页面(完全依赖全局数据流,几乎没有自己的状态)
|
||||
@@ -409,7 +409,7 @@ const App = memo(function App() {
|
||||
const [state, dispatch] = useReducer(appReducer, new State())
|
||||
|
||||
return (
|
||||
<AppDispatch.Provider value={dispaych}>
|
||||
<AppDispatch.Provider value={dispatch}>
|
||||
<Count count={count}/>
|
||||
<Name name={name}/>
|
||||
</AppDispatch.Provider>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user