anjia / blog Goto Github PK
View Code? Open in Web Editor NEW博客,积累与沉淀
博客,积累与沉淀
W3C 通过 status code 来表示 specifications 的 maturity。
CSS WG 使用以下状态码,从 least 到 most stable:
ED
Editors' Draft 编辑草案(不是 W3C Technical Report)FPWD
First Public Working Draft 首个公开工作草案 ✔WD
Working Draft 工作草案 ✔(0 || 多个)
LC
LCWD
Last Call Working Draft
CR
,除非有重大问题提出CR
之前CR
Candidate Recommendation 候选推荐标准 ✔✔
PR
Proposed Recommendation 提案推荐标准 ✔✔
CR
到PR
,需要全面的 test suite 和实现报告,以证明每个特性都在至少2款浏览器里实现了REC
WD
或CR
PER
Proposed Edited Recommendation 已修订的提案推荐标准REC
Recommendation 推荐标准,通常称之为 standard,即事实标准 ✔✔
SPSD
Superseded Recommendation 被取代的推荐标准(缺少足够的市场相关性)ret
Retired 退役的Note
Group Note 工作组说明,不打算成为标准的文档。已经停止使用了
https://www.w3.org/Style/2011/CSS-process
https://www.w3.org/2018/Process-20180201/#Reports
immutable 不可变的
immutability 不变性
mutating data 变异数据
编写 immutable 的 JS 代码,是个比较好的实践。已经有库 Immutable.js 可以帮我们实现这个特性了。这篇博客来聊下,在 ES6+ 里如何使用 Immutable 特性。
为什么 immutability 很重要?因为,变异数据会让代码不易阅读,也容易引入bug。
对于基本类型(比如 number 和 string),书写 immutable 代码是非常简单的,因为基本类型自己不会变。指向基本类型的变量一直指向实际的值,如果你把它赋值给了另一个变量,那另一个变量是得到了该值的一个新拷贝。
对象(和数组)就不一样了,因为它们传的是引用。在这种情况下,新变量和原始变量是指向的同一个对象。不论你修改新变量还是原始变量,都会 mutate 该对象。先来感受下。
const person = {
name: 'anjia',
age: 18
};
const newPerson = person;
newPerson.age = 30;
console.log(newPerson === person); // true
console.log(newPerson, person); // age 都是30了
这就是问题的所在。当你修改了 newPerson
,我们竟然也自动修改了旧对象 person
。在大多数情况下,这是不希望的行为,也是不好的编码实践。
那下面,我们看看如何解决这个问题。
不传引用,我们可以创建一个全新的对象。
const person = {
name: 'anjia',
age: 18
};
const newPerson = Object.assign({}, person, {
age: 30
});
console.log(newPerson === person); // false
console.log(newPerson, person); // newPerson 是30岁,person 还是18岁
Object.assign
是个 ES6 的新特性,它把所有对象合并到第一个。
这样,就保持了旧变量 person
的独立性和完整性,我们把它称之为 immutable。
在 ES6 里,我们有更简洁的写法。可以用 object spread 操作符 ...
,这样:
const person = {
name: 'anjia',
age: 18
};
const newPerson = {
...person,
age: 30
};
console.log(newPerson === person); // false
console.log(newPerson, person); // newPerson 是30岁,person 还是18岁。同上
那么,如何删除一个属性呢?当然,不能用 delete,因为它会 mutate 到原始值。我们可以这样:
const person = {
name: 'anjia',
gender: 'female',
age: 18
};
const property = 'age'; // 删除age属性
const newPerson = Object.keys(person).reduce((obj, key) => {
if(key !== property){
return {...obj, [key]: person[key]}
}
return obj
}, {});
console.log(newPerson === person); // false
console.log(newPerson); // 只有 name 和 gender
console.log(person); // 有 name, gender, age
呃,好吧,删除的话我们需要自己写整个逻辑代码。你可以把它封装成一个公共方法。
下面的例子,以 mutating 的方式向数组里添加新项。
const names = ['an', 'jia'];
const newNames = names;
newNames.push('zora');
console.log(newNames === names); // true
console.log(newNames, names); // 都是 ["an", "jia", "zora"]
解决办法,思路同上。
const names = ['an', 'jia'];
const newNames = [...names, 'zora'];
console.log(newNames === names); // false
console.log(newNames); // ["an", "jia", "zora"]
console.log(names); // ["an", "jia"]
这样我们就创建了一个新数组newNames
,而且还能让老数组names
保持自身的独立性和完整性。
关于数组的,还有一些方法也能非常方便地生成新数组,而不影响老值。比如 map
filter
等。详见之前的一篇博客数组遍历。看代码(点进去链接看看),有没有觉得写 immutable 的代码更方便了。再配合着箭头函数,就更简洁了。它们每次都返回一个全新的数组。
当然,有一个例外就是sort()
const names = ['zora', 'anjia', 'an', 'jia'];
const newNames = names.sort();
console.log(newNames === names); // true
console.log(newNames); // 都输出 ["an", "anjia", "jia", "zora"]
console.log(names);
有没有解决办法呢?有,如下:
const names = ['zora', 'anjia', 'an', 'jia'];
const newNames = names.slice().sort(); // 利用 slice(),虽然有点 hacky
console.log(newNames === names); // false
console.log(newNames); // ["an", "anjia", "jia", "zora"]
console.log(names); // ["zora", "anjia", "an", "jia"] 原值
如上,现代JS,可以让我们轻松实现 immutability。良好的编码,可以避免让JS变得不可预测。
每次都创建新对象会耗费时间和内存哦?嗯~是的,它会带来一点开销。但是,与它带来的优势来比,这点缺点可以忽略了。
Object.observe(object, callback)
是非常重的,且开销也很大。如果是 immutable,那可以用 oldObject === newObject 来判断
,会很省内存哦REF:https://wecodetheweb.com/2016/02/12/immutable-javascript-using-es6-and-beyond/
目录
cookie | localStorage | sessionStorage | |
---|---|---|---|
作用域 | origin + path 当 path 是 '/' 时,则是 origin |
origin | origin + tab |
失效期 | 一般由服务器生成,并设置失效时间;若在客户端设置,默认是浏览器关闭/max-age | 持久型/主动删除 | 当前页签关闭 |
大小限制 | 每条 cookie 约 4KB / 个数限制 | 大约 5MB | |
HTTP 请求是否携带 | 是 | 否 | |
安全 | 尽量加密 / HTTP only | 若取, 注意XSS攻击 | |
使用时 | 有库-封装 | 也可封, eg.方便存 JSON, Array 等 |
客户端存储时,别人都可随便修改
需注意安全方面。eg.加密、防止 XSS 攻击、防止恶意修改
当涉及敏感信息时,尤其注意。eg.钱、订单
大小限制,不同浏览器的实现会略不一样。
RFC 2965 的推荐标准:
cookie 的设计比较早,它作为 HTTP 协议的一种扩展,数据会自动在客户端和服务器之间传输。
所以,要在 cookie 里放数据时,尤其考虑此特性。以及安全性。
cookie 的限制:
它和 localStorage 的唯一区别,就在于有效期。
说说处理它时的注意事项:
setItem()
时记得捕获异常
这里有个 localStorage 的在线例子,可以感受下浏览器兼容性
https://mdn.github.io/dom-examples/web-storage/
我们都知道,CSSOM 是 CSS 的对象模型,它提供了一系列方法来访问元素上各个属性的值。
CSS Typed OM(CSS 类型化的对象模型),单纯看名字,它只比 CSSOM 多了个 Typed。它是 CSS 的 object-based API,把 CSS value 的字符串值转成了 JS 对象。是 CSS Houdini #23 的一部分。
CSS OM | CSS Typed OM |
---|---|
介绍 | CSS Typed OM |
values 都是 string | values 都是 JS object |
给 CSS values 增加了 types, methods 和 a proper object model |
|
element.style |
元素 .attributeStyleMap 样式规则 .styleMap |
两方法都返回StylePropertyMap 对象是个 map-like object,可以用 get/set/keys/values/entries |
|
写法简单 | 写法冗长了点 |
代码更健壮 性能更好 |
接下来,我们重点看下它是如何让代码更健壮性能更好的。
特性检测
window.CSS && CSS.number
el.attributeStyleMap.set('opacity', '0.3');
el.attributeStyleMap.get('opacity').value === 0.3 // true
el.attributeStyleMap.get('opacity').value += 0.1 // 再也不用担心值是 0.30.1 了
el.attributeStyleMap.set('z-index', CSS.number(15.4))
el.computedStyleMap().get('z-index').value === 15 // 自动四舍五入,处理成 15
el.attributeStyleMap.set('opacity', 3)
el.computedStyleMap().get('opacity').value === 1 // 值始终在有效范围之内
// 之前的写法
el.style.backgroundColor
el.style['background-color']
requestAnimationFrame
和 animationWorklet
更详细的 API,见 API Basics
要理解 CSS specifications,需要理解规范构建的 context, vocabulary 和 fundamental concepts。
注意:
另外:
var now = new Date()
now.toLocaleString() // 2019/1/7 下午12:30:13
now.toLocaleDateString() // 2019/1/7
now.toLocaleTimeString() // 下午12:30:13
now.toDateString() // Mon Jan 07 2019
now.toGMTString() // Mon, 07 Jan 2019 04:30:13 GMT
now.toISOString() // 2019-01-07T04:30:13.857Z
now.toJSON() // 2019-01-07T04:30:13Z
now.toString() // Mon Jan 07 2019 12:30:13 GMT+0800 (**标准时间)
now.toTimeString() // 12:30:13 GMT+0800 (**标准时间)
now.toUTCString() // Mon, 07 Jan 2019 04:30:13 GMT
CSS 属性列表的索引,供参考
ED
今天,和大家聊聊 CSS 是如何确定图像的显示大小的。
先来看个例子,热热身。
上面这张图像的原始尺寸是:宽 54px 高 49px。
那么,在以下代码中,每张图像显示的最终尺寸是多少?
图像由<img src="">
指定,代码如下:
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png">
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png" width="30" height="30">
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png" width="30">
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png" height="30">
图像由background-image
指定,代码如下:
<style>
.img {
display: inline-block;
background-color: #eee;
background-image: url('https://p1.ssl.qhimg.com/t01068da1826ad05875.png');
background-repeat: no-repeat;
background-size: auto; /*auto 是默认值*/
}
</style>
<span class="img" style="width: 100px; height: 100px;"></span>
<span class="img" style="width: 30px; height: 30px;"></span>
<span class="img" style="width: 30px; height: 30px; background-size: 10px 10px;"></span>
<span class="img" style="width: 30px; height: 30px; background-size: contain;"></span>
<span class="img" style="width: 100px; height: 100px; background-size: cover;"></span>
以上 9 道题,你都答对了吗?
为了方便讨论,我们先来认识四个术语:
width
height
background-size
中的一个或多个指定的通常情况,计算图像大小的默认过程是:
初听起来有些绕,我们用刚才提到的例子具象下这个过程。
光栅图像是有三个固有尺寸的。以开头给出的 Logo 图像为例,它的固有尺寸分别是:
<img>
我们先来看用<img src="">
指定的那四个:
demo1.
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png">
没有指定大小,那就用固有尺寸。所以,最终显示的尺寸是宽 54px,高 49px
demo2.
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png" width="30" height="30">
有指定的宽和高,所以,最终显示的尺寸是宽 30px,高 30px
demo3.
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png" width="30">
只有一个指定的宽,那就用固有宽高比计算出高来。所以,最终显示的尺寸是宽 30px,高 30/(54/49)=27.22px
demo4.
<img src="https://p1.ssl.qhimg.com/t01068da1826ad05875.png" height="30">
只有一个指定的高,那就用固有宽高比计算出宽来。所以,最终显示的尺寸是宽 30*(54/49)=33.06px,高 30px
以上四个示例的 UI 依次是:
background-image
接下来,看用background-image
指定的五个。
在这个上下文里,背景区域的大小即图像的默认对象大小,background-size
属性提供指定大小。
background-size
有两个关键字contain
和cover
,它们分别对应包含约束和覆盖约束。
demo1.
<span class="img" style="width: 100px; height: 100px;"></span>
auto
是background-size
的默认值,意思是按图像的固有尺寸来,所以最终显示的尺寸是宽 54px,高 49px
demo2.
<span class="img" style="width: 30px; height: 30px;"></span>
同上,auto
按图像的固有尺寸来,所以最终显示的尺寸是宽 54px,高 49px
demo3.
<span class="img" style="width: 30px; height: 30px; background-size: 10px 10px;"></span>
这里background-size: 10px 10px
给出了具体的指定大小,所以最终显示显示的尺寸就是宽 10px,高 10px
demo4.
<span class="img" style="width: 30px; height: 30px; background-size: contain;"></span>
根据contain
的含义,包含约束要在背景框里尽可能的大。背景框宽 30px 高 30px,图像固有宽 54px 固有高 49px,所以包含约束取宽 30px,高根据固有宽高比算出来 30/(54/49)=27.22px,也就是指定大小是宽 30px 高 27.22px。对于背景区域未覆盖到的地方将会用背景色来填充。所以最终显示的尺寸是宽 30px 高 27.22px。
demo5.
<span class="img" style="width: 100px; height: 100px; background-size: cover;"></span>
根据cover
的含义,覆盖约束要在大于等于背景框的前提下尽可能的小。背景框宽 100px 高 100px,图像固有宽 54px 固有高 49px,所以覆盖约束取高 100px,宽根据固有宽高比算出来 100*(54/49)=110.20px,也就是指定大小是宽 110.20px 高 100px。 对于超出背景区域的部分,会被裁切掉,所以最终显示的尺寸是宽 100px 高 100px。
以上五个示例的 UI 依次是:
width
height
background-size
background-size
<img>
时,也有个相应的属性可以调整图像大小,即 object-fit嗨,你好,我叫安佳,是 360 搜索事业部的一名前端开发工程师。今年5月,我有幸加入了 W3C 的 CSS 工作组,成为其中的一员。第一次参与工作组讨论的是关于 [css-grid-2] Allow minmax where max wins over min,很开心自己的提议被标准采纳了,预计会在 CSS Grid Layout Module Level 2 里实现。
期间,看到了一个关于要 CSS 支持原生嵌套的议题 [css-nesting] request to pick up the css-nesting proposal。当时觉得这个特性很好,于是就表达了自己的观点。一周之后,CSS 工作组在周会上对它进行了讨论,但是打的标签依然是 unknown/future spec
。又过了两周,看起来并没有要在下一个模块里实现此特性的计划,也没有要商讨的安排。
这么有用的嵌套功能和scope
特性,为什么一直坐在冷板凳上呢?于是,我就想探究下原因。这篇文章就是研读此 Issue 及相关规范的成果,主要有这三部分:
2012年4月13日,CodePen 的联合创始人 Chris Coyier 抱怨 CSS 的类名不支持命名空间,导致要写好多重复的选择器。
2016年2月2日,微软的项目经理 Kenneth Auchenberg 说如果 CSS 支持了变量和嵌套,他将不再使用预处理器。
2016年12月8日,《CSS揭秘》的作者 Lea Verou 调研了使用 CSS 预处理器的首要原因(单选题),有 1838 个人参与了投票,最终并列第一的两个理由是嵌套和变量。她觉得是时候该重新考虑 CSS 原生嵌套的问题了。
2017年7月13日,集设计和开发才能于一身的 UI/UX 自由工作者 Sara Soueidan 说嵌套是她最想要的 CSS 功能。
2017年8月15日,node-inspect 的作者 Jan Olaf Krems 说 cssnext 把嵌套定义成了“明天的 CSS”,但他还是想看到原生的 CSS 嵌套,毕竟 JS 的生态系统已经证明避免“每个人都使用自己的半标准语言”绝对是健康的。
2018年2月23日,Lea Verou 再次发声,说她现在还在用 CSS 预处理器写嵌套,一旦 CSS 支持了原生嵌套,她就果断弃用预处理。
2018年5月25日,postcss-preset-env 的作者 Jonathan Neal 再次提议重新考虑下让 CSS 支持原生嵌套(也就是本文章的切入点),这引来了一波热议。
其实,早在2014年4月3日,W3C 就发布过一个 CSS范围(scoping)模块 的工作草案;2015年9月23日,谷歌的工程师 Tab Atkins 也发布过一个 CSS嵌套模块 的编辑草案。那个时候,CSS 工作组也讨论过嵌套的问题,但并未通过社区的同意(见会议纪要)。
针对 Jonathan Neal 这次的提议,CSS 工作组的讨论流程如下:
图1. CSS工作组的讨论流程
scope
能否真正满足开发人员的需求还不明朗scope
是两个维度的特性,建议先实现已经比较成熟的嵌套最终的结论是,新增 CSS 嵌套模块,默认 ED(Editor Draft,编辑草案) 阶段,由 Tab Atkins 担任编辑,并收集相关 Issues,直到该特性成为 FPWD(First Public Working Draft,首个公开工作草案)。
ED
Editor Draft 编辑草案
WD
Working Draft 工作草案
CR
Candidate Recommendation 候选推荐标准
PR
Proposed Recommendation 提议推荐标准
REC
Recommendation 推荐标准(最稳定的)
关于标准的诞生过程,可查看 World Wide Web Consortium Process Document
CSS Nesting Module Level 3 里定义了 CSS 嵌套,它新增了一个新的选择器:嵌套选择器 &
a, b {
& c { color: blue; }
}
/* 等价于 */
a c,
b c { color: blue; }
看了上面的写法,我想肯定有小伙伴要问了:那个前缀 &
能省略不写吗?
对此,草案里的解释是:现有的 CSS 解析都是通过一个单独的前瞻符(lookahead token)来区分各种选择器的,如果新增的嵌套语法不写前缀的话,那一段文本就没法提前知道它到底是一个 CSS 声明还是一个 CSS 选择器了,这会非常不利于浏览器的实现。
前瞻符,诸如:
#
ID 选择器.
类选择器[]
属性选择器*
通用选择器:
伪类::
伪元素
另外,如果省略了 &
也就没法区分 #foo { .bar {} }
到底是复合选择器 #foo.bar
还是组合选择器 #foo .bar
了。
草案里定义了两种嵌套方法:直接嵌套和 @nest
规则
直接嵌套,即直接以嵌套选择器 &
开头
.foo {
color: blue;
& > .bar { color: red; }
}
/* 等价于
.foo { color: blue; }
.foo > .bar { color: red; }
*/
.foo {
color: blue;
&.bar { color: red; }
}
/* 等价于
.foo { color: blue; }
.foo.bar { color: red; }
*/
.foo, .bar {
color: blue;
& + .baz, &.qux { color: red; }
}
/* 等价于
.foo, .bar { color: blue; }
.foo + .baz,
.bar + .baz,
.foo.qux,
.bar.qux { color: red; }
*/
/**
* 以下写法都是无效的
*/
.foo {
color: red;
.bar { color: blue; }
}
/* 无效原因:没有嵌套选择器 & */
.foo {
color: red;
.bar & { color:blue; }
}
/* 无效原因:& 没有在组合选择器的第一位 */
.foo {
color: red;
&.bar, .baz { color: blue; }
}
/* 无效原因:列表的第二个选择器里没有嵌套选择器 & */
@nest
规则.foo {
color: red;
@nest & > .bar {
color: blue;
}
}
/* 等价于
.foo { color: red; }
.foo > .bar { color: blue; }
*/
.foo {
color: red;
@nest .parent & {
color: blue;
}
}
/* 等价于
.foo { color: red; }
.parent .foo { color: blue; }
*/
.foo {
color: red;
@nest :not(&) {
color: blue;
}
}
/* 等价于
.foo { color: red; }
:not(.foo) { color: blue; }
*/
/**
* 以下写法都是无效的
*/
.foo {
color: red;
@nest .bar {
color: blue;
}
}
/* 无效原因:没有嵌套选择器 & */
.foo {
color: red;
@nest & .bar, .baz {
color: blue;
}
}
/* 无效原因:列表里并非所有的选择器都包含嵌套选择器 & */
在此特别感谢,感谢 @cncuckoo(李松峰老师)对本文提出的大量指导建议,让我学到了很多,尤其是极其严谨的工作态度,以及以读者为出发点的行文思路。
看完本篇文章,你有什么想说的吗?欢迎留言。
当然,你也可以去 CSS 工作组的官方 github 上 w3c/csswg-drafts 提 Issue。若是和嵌套相关的,则 Issue 的标题格式是“[css-nesting]...”;若是和scope
相关的,则标题格式是“[css-scoping]...”。诚邀大家提出建设性的意见/建议。
相关规范:
本文章仅代表个人观点,与 CSS 工作组无关。特此说明
FPWD
WD
CR
REC
等,才是官方规范规范 | 成熟度 | 说明 | |
---|---|---|---|
1 | CSS Painting API 1 | CR |
用JS自定义CSS图像类型 |
2 | CSS Layout API Level 1 | FPWD |
用JS自定义布局 |
Worklets 1 | FPWD |
在渲染引擎的各个阶段执行脚本,独立于主JS | |
3 | CSS Animation Worklet 1 | FPWD |
可控制一组动画效果的脚本动画 |
4 | CSS Typed OM 1 | WD |
将CSSOM的值的字符串转成JS对象,性能好点 |
5 | CSS Properties and Values API 1 | WD |
注册新的CSS属性,可定义类型/继承/赋初始值 |
Box Tree API 1 | Idea | 访问 boxes 信息的 API | |
Font Metrics API | Idea | 提供基本的字体指标 | |
CSS Parser API | 提供CSS解析的API,移到了 WICG 仓库 |
7个今年还在更新维护中
Draft:Draft Community Group Report,社区小组报告草案
Idea:还在收集想法当中
WICG:Web Platform Incubator Community Group,Web平台孵化器社区小组
结合浏览器的实现情况及标准的进展,按成熟度降序排列:
概述 HTTP 协议:Web 的基础构件、HTTP 的核心技术
Schedule 见 TPAC 2018 / CSS WG
src:local()
font 唯一名字匹配 ambiguous & restricts matched localeIdea
<style>/<link>
里使用 CSSStyleSheets 吗?ED
text-spacing
属性FPWD
ED
共4个
- Quantum 初探:介绍了 Quantum 项目的由来和概况,也顺便介绍了 Servo 的小历史
- Servo 的设计架构:即本篇文章,将介绍 Servo 的基于任务的设计架构,重点介绍并行并发的策略
对,我就是 Servo 的官方 Logo
Servo 是一款现代化的高性能浏览器引擎,既支持常规应用,也支持嵌入使用。官网 https://servo.org
她由 Mozilla 开发,由三星集团移植到 Android 系统和 ARM 处理器,旨在创造一个大规模并行计算的环境,Servo 也与 Rust 编程语言有着共生的关系。源自 https://zh.wikipedia.org/wiki/Servo
Servo 是一个新的 Web 浏览器引擎。她的目标是创建一个多层级的高并发架构,同时在架构层面消除与错误的内存管理、数据竞争相关的常见 bug 和安全漏洞。
因为 C++ 不适合处理这类问题,所以 Servo 是用 Rust 语言编写的。Rust 在设计的时候充分考虑了 Servo 的需求,它提供了任务并行的基础架构和强类型系统,从而保证了内存安全、避免了数据竞争。
在设计的时候,Servo 的架构师们会优先考虑现代 Web 平台的以下特性:高性能、动态、富媒体应用,可能会牺牲一些无法优化的特性。他们想知道一个快速响应的 Web 平台是什么样子的,然后再实现它。
Servo 专注于实现一个功能完备的 Web 浏览器引擎和可靠的嵌入式引擎,前者(Web 浏览器引擎)使用了基于 HTML 的用户界面 Browser.html。尽管 Servo 最初只是一个研究型项目,但在开发它的时候就以提供可用于生产环境的代码为目标。目前,Servo 的一些组件已经迁移到了 Firefox 浏览器。
关于集成到 Firefox 中的 Servo 组件,可查看 Jack Moffitt 的演讲视频 Web Engines Hackfest
并发是拆分任务以便交叉执行;并行是同时执行多个任务以提高速度。Servo 在以下环节中用到了并行和并发。
显示列表
分成子树,并行渲染子树,并将其内容保留在 GPU 上。GC,Garbage Collection,垃圾回收
图1. 任务监管图,源自 servo/wiki/Design
图2. 任务通信图,源自 servo/wiki/Design
我们可以把每个 constellation(见“附录.术语”小节)实例看做是浏览器的单个页签或者窗口,它管理着接收输入的任务管道,针对 DOM 运行 JavaScript,执行布局,构建显示列表
,将显示列表
渲染到瓦片上,最后把最终图像合成到屏幕上。
这个管道由四个主要任务组成:
显示列表
,显示列表
会被发送到渲染任务。显示列表
,并将可见部分渲染到一个或多个瓦片上,尽可能并行。管道中的多任务通信涉及到两种复杂的数据结构:DOM 和显示列表
。DOM 从内容传到布局,显示列表
从布局传到渲染。找出一种有效且类型安全的方式来表示、共享和传递这两种数据结构是该项目的诸多挑战之一。
Servo 的 DOM 树节点是有版本控制的,它们可以在单个 writer 和多个 reader 之间共享。DOM 使用写时复制(copy-on-write)的策略允许当有多个 reader 时 writer 也能修改 DOM。writer 总是内容任务,reader 总是布局任务或其子任务。
DOM 节点是 Rust 值(Rust value),而 Rust 值的生命周期由 JavaScript 垃圾收集器管理。JavaScript 直接访问 DOM 节点,而没有依赖 XPCOM 或其它类似的基础设施。
DOM 接口目前不是类型安全的,这可能会导致不正确的节点管理。消除这类不安全是该项目的一个必要的高优先级目标;由于 DOM 节点具有复杂的生命周期,这将会带来一些挑战。
Servo 的渲染完全由显示列表
驱动,显示列表
是由布局任务创建的一系列高级绘图命令。Servo 的显示列表
是完全不可变的,因此它可以被同时运行的多个渲染任务所共享。这与 Webkit 和 Gecko 的渲染器不同:WebKit 的渲染器没有使用显示列表
;Gecko 的渲染器使用了显示列表
,但它在渲染期间还会查询额外的信息。
目前,Servo 使用的脚本引擎是 SpiderMonkey(可插拔引擎是一个长期的、低优先级的目标)。每个内容任务都有自己的 JavaScript 运行时。DOM 绑定使用原生的 JavaScript 引擎 API 而不是 XPCOM。从 WebIDL 自动生成绑定是一个高优任务。
与 Chromium 和 WebKit2 类似,Servo 的架构师们打算做一个可信任的应用程序进程和多个不太可信的引擎进程。高级 API 实际上是基于 IPC 的,非 IPC 实现可能用于测试和单进程用例(虽然预计最糟糕的时候也会用于多进程)。引擎进程将使用操作系统沙箱工具来限制对系统资源的访问。
目前,Servo 并不打算像 Chromium 那样采用极端沙箱(extreme sandboxing),主要是因为锁定沙箱会导致大量的开发工作(特别是在 Windows XP 和旧版 Linux 等低优先级的平台上),并且该项目的其它方面的优先级更高一点。Rust 的类型系统还为内存安全漏洞增加了一层重要的防御功能,虽然仅凭这一点并不能使沙箱在防御不安全代码、类型系统中的错误以及第三方/主机库等方面变得不那么紧迫,但相对于其他浏览器引擎它确实能显著减少 Servo 的攻击面。此外,Servo 的架构师们对某些沙箱技术有性能方面的顾虑(例如,将所有 OpenGL 调用代理到单独的进程)。
网页依赖于各种各样的外部资源,而这些资源具有很多的检索和解码机制。这些资源会被缓存在多处,比如磁盘、内存。在并行浏览器的设置中,这些资源一定会在并发的多个 worker 之间调度。
通常,浏览器是单线程的,会在“主线程”上执行 I/O,而“主线程”同时又担负着大部分的计算任务,这就会导致延迟问题。而 Servo 中没有“主线程”,所有外部资源的加载都由一个资源管理任务来处理。
浏览器有很多缓存,而 Servo 的基于任务的架构意味着它可能会拥有比现有浏览器引擎还多的缓存(例如,我们在拥有全局任务缓存的同时,也拥有着一个本地任务缓存,它存储着来自全局缓存的结果,以通过调度程序来保存往返记录)。Servo 应该有一个统一的缓存机制,以便在低内存的环境中也运行良好。
constellation
:该线程控制相关网页内容。在支持多页签的浏览器中,可以把它当做单个页签的拥有者;它封装了会话历史记录,知道 frame 树中的所有 frame,是每个 frame 管道的拥有者。管道(pipeline)
:为特定文档封装了脚本线程、布局线程和渲染线程之间的通信。每个管道都有一个全局唯一的 id,可以从 constellation 里访问到它。脚本线程/脚本任务(script thread/script task)
:这个线程执行 JavaScript,并存储同源下所有文档的 DOM 表示。它可以把从 constellation 接收到的输入事件转换为规范里定义的 DOM 事件,也可以在收到新页面的时候调用 HTML 解析,也可以为事件评估 JS。布局线程(layout thread)
:这个线程负责将 DOM 树布局到特定文档的层(layer)上。它会收到来自脚本线程的命令,要么是为渲染线程生成一个新的显示列表
,要么是为脚本线程返回页面的布局结果。显示列表(display list)
:一个具体的渲染说明(高级绘图命令)列表。显示列表
是发生在布局之后的,因此所有的项都有相对堆叠上下文的像素位置,并且已经应用了 z-index,所以后加入显示列表
的项将始终在其它项的上面。渲染线程/绘制线程(renderer thread/paint thread)
:这个线程负责将显示列表
转换成一系列的绘图命令。该绘图命令会将关联文档的内容渲染在一个缓冲区里,之后会被发送到合成器。合成/合成器(Compositor)
:负责 Web 内容的合成渲染,并将它们尽可能快地显示在屏幕上。也负责从操作系统接收输入事件,并将它们转发到 constellation 线程。本文主要介绍了 Servo 的设计概况,重点介绍了它基于任务的整体架构及其四个主要任务(也称“线程”,在 Servo 的这个上下文里),即脚本任务、布局任务、渲染任务、合成任务。下图便是对上述内容的一个总结,希望对大家有所帮助和启发。
后续,我会继续探索更多详细内容,敬请期待。关于 Quantum 和 Servo,如果您有其它更想知道的,欢迎留言。
感谢 @cncuckoo(李松峰老师)和 @liuguanyu(二哥)对本文提出的指导意见和建议。手动送花花。🌹
WIP, Work In Progress, 开发中(work in progress, do not merge yet)
PTAL, Please Take A Look, 帮我看下(请别人 review 自己的 PR)
LGTM, Looks Good To Me, 看起来不错, 没有问题(别人 review 完 PR 之后)
RFC, Request For Comments, 请求评论, i.e. I think this is a good idea, lets discuss
AFAIK / AFAICT, As Far As I Know / Can Tell, 据我所知
IMHO, In My Humble Opinion, 以我的拙见(多用于邮件和网络)
FYI, For your information, 供你参考
CC, Carbon Copy, 抄送(邮件)
AFK, Away From the Keyboard, 稍后回来
ACK, ACKnowledgement, 同意, i.e. agreed/accepted change
NACK/NAK, Negative ACKnowledgement, 不同意, i.e. disagree with change and/or concept
$ vim main.rs # 新建文件
$ rustc main.rs # 编译
$ ls
main.rs # 源文件
main # 可执行文件
$ ./main # 执行
Hello, world!
main
函数,它是每个可执行的 Rust 程序首先执行的代码rustfmt
自动格式化工具(后续会将它包含在标准 Rust 发行版中);
结尾println!
调用了一个 Rust 宏println
是调用函数!
时,就是宏,而不是普通函数rustc
Rust 的编译器(类似于C/C++的gcc
/clang
).ext
后缀的,其它平台,无后缀.pdb
后缀是包含调试信息的normal
和important
字段),将其引入到 SelectorMap::-servo-details-summary
::-servo-details-content
::-servo-details-
伪类都是私有的,i.e. 它们只解析来自 User-Agent 样式表里的*|*
选择器的规则),它们被直接应用到元素的 style,如果展示::-servo-details-content
是这种伪类元素的一个例子,在 UA 样式表中的所有规则-有选择器 *|*::-servo-details-content
(也仅有这些)被评估通过元素的style(除去display
的值,那会被layout重写)::-servo-details-summary
lazy伪元素(关于它,只需要知道它是否在open
细节元素中)https://github.com/servo/servo/blob/master/docs/components/style.md
CSS 是一门语言,描述 HTML、XML 等 structured documents 在 screen, paper 等媒介上的 rendering。
https://drafts.csswg.org/css-display
这个模块描述了:
处于 at-rist 状态的特性,可能会在CR
阶段删掉而不用再发布新的CR
了:
::first-letter
display: run-in
at-rist 是 W3C Process 的一个术语,并不是说这个特性后续会被 dropped 或者 delayed。
而是 WG 觉得此特性实现成本略高,在短期内实现有难度,
所以在将本模块升级为PR
时,可以删除该功能,而不用再发布一个新的CR
了。
CSS 处理的源文档,是组织成 elements 和 text nodes 的 tree。CSS 将它 render 到 canvas 上(比如 screen, paper 或者 audio stream)。为了 render,CSS 会生成一个中间结构 box tree ,代表渲染文档的 formatting structure。
在创建 box tree 树之前,CSS 会先用 cascading 和 inheritance,将每个 CSS 属性的计算值分配给中的每个 element 和 text-node。
接着,对每个 element,CSS 会根据其 display 的值生成零个或多个 boxes
display:list-item
会生成一个 principal block box 和一个 marder boxdisplay:none
dipaly:contents
Boxes 经常就叫它们的 display 类型,比如由
display:block
元素生成的 box 就叫 block box 或者 block。元素的 principal box 的 parent box 是它最近的祖先元素 principal box
box 和生成它的 element 有相同的样式,除非另有说明。通常,可继承的属性,会分配给 principal box,然后通过 box tree 继承到由同一个 element 生成的其它全部 box。不可继承的属性,默认会应用到 principal box;但是当 element 生成多个 boxes 的时候,它有时会定义成应用到不同的 box,比如:应用到 table 元素的 border 属性,会应用到它的 table box,但不会应用到它的 principal table wrapper box。如果值计算的过程改变了这些 boxes 的样式,那么元素的样式会被 requested (比如通过 getComputedStyle()
),element reflects,对每个属性,值从 box 到应用该属性的 box。
类似的,每个相邻 text nodes 的连续序列生成一个包含它们内容的 text run ,它的样式和生成它们的 text nodes 相同。当然,如果序列不包含文本,那它就不生成 text run 了。
anonymous box 不和任何 element 关联。在有些情况下生成 anonymous boxes,是为了修复 box tree,i.e, 当它需要特定的嵌套结构,但是 element tree 里生成的 boxes 没有提供这种嵌套结构时。e.g. table cell box 就需要一个特定类型的父框 table row box,即便它的父不是 table row box。不同于生成元素的 boxes(它的样式通过 element tree 严格继承),anonymous boxes 是从它的 box tree 父系来继承的。
在 layout 的过程中,boxes 和 text runs 会被分成多个 fragments 。这当什么时候会发生呢?比如,当一个 inline box 或者 text run 跨行时,或者一个 block box 跨页/列时。所以一个 box 由一个或者多个 box fragments 组成;一个 text run 由一个或者多个 text fragments 组成。更多关于 fragmentation 的,可以查看 [css2-break]。
关于 "aural" box tree,可查看 CSS Speech Module
ps. CSS WG 已经停止了在该模块上的工作
::first-line
和::first-letter
initial
inherit
unset
若属性可继承,则值同inherit
, 否则同initial
florian ... but what we need to worry about is its effects on users, rather than on the mood of developers.
dbaron: Have to think about what happens when web pages start using these things.
... But either way we need a spec about them, so we know what to do about them.
fantasai: In many cases, a feature started out in one camp, was adopted and further developed by another, and passed back and forth until it wound up in specs and implementations.
fantasai: Most modules, however, are a mix. And the design of many features is the result of input from multiple sources.
依赖 Node.js 8.9+, 推荐 8.11.0+ / 10.14.0+ brew upgrade node
npm uninstall vue-cli -g # 若安装了旧版的 vue-cli,卸载下
npm install -g @vue/cli # Vue CLI 3
vue --version # 3.x
vue 3.1.3
Vue CLI 本身使用了一套基于插件的架构
用 Vue CLI 3.1.3 创建项目:
若保存了 preset,会在文件
~/.vuerc
里
这样,下次就不用命令行提示了,直接修改此文件即可
Vue CLI 里,@vue/cli-service
安装了vue-cli-service
命令
三个脚本:都有各自的 --options
serve
: 开发环境,构建。
vue.config.js
里的devServer
字段配置开发服务器build
: 线上,构建。会在dist/
目录产生一个可以用于生产环境的包
inspec
: 可以审查 Vue CLI 项目的 webpack configlint
:npx vue-cli-service help
style::traversal::recalc_style_at
style::traversal::recalc_style_at
函数,计算单个节点的样式style::traversal
模块,遍历DOM树style
是个 Crate模块 | 说明 |
---|---|
animation | CSS 的 transition 和 animation |
applicable_declarations | applicable(适用的)声明管理 |
attr | 解析 DOM attributes 的表示 |
author_styles | 一组作者样式表及其计算表示,例如用于 ShadowRoot 和 XBL 的 |
bezier | 贝塞尔曲线 |
bloom | 样式 bloom filter 是一项优化手段,用在深层后代选择器匹配时 |
computed_values | computed 值 的类型 |
context | 计算样式的上下文 |
counter_style | @counter-style 规则 |
custom_properties | 支持层叠变量的自定义属性,CSS Custom Properties for Cascading Variables Module Level 1 |
data | 样式计算中的每个节点的数据 |
dom | 用于从样式计算中访问DOM的类型和特征 |
dom_apis | 一些 DOM API 的通用实现,以便它们可以在 Servo 和 Gecko 间共享 |
driver | 遍历 DOM 树。遍历以顺序模式开始,当它发现 work 的时候有选择的并行 |
element_state | 声明元素可以在 |
encoding_support | 从字节解析样式表(不是从字符串) |
error_reporting | 用于报告解析错误的类型 |
font_face | @font-face 规则 |
font_metrics | 从样式系统访问字体指标 |
hash | 在 Gecko 模式下重新导出 hashglobe 类型,在 Servo 模式下重新导出 stdlib hashmap |
invalidation | 与无效样式相关的不同代码 |
logical_geometry | 在 flow-relative 空间中的几何信息 |
macros | 各种宏助手 |
matching | CSS 选择器匹配的高级接口 |
media_queries | 媒体查询 |
parallel | 并行遍历 DOM 树的实现 |
parser | 解析 CSS 代码的上下文 |
properties | 样式系统支持的 CSS 属性。由 build.rs 从 properties.mako.rs 模板生成 |
rule_cache | 从规则节点到 computed 值的缓存,以便缓存重置属性 |
rule_tree | 规则树 |
scoped_tls | Stack-scoped thread-local storage for rayon thread pools |
selector_map | 一种数据结构,可通过本地名称,ID和哈希有效地索引包含选择器的结构 |
selector_parser | 样式系统支持的伪类和伪元素 |
servo | 样式系统的和 servo 相关的 |
shared_lock | 受同一个锁保护的不同对象 |
sharing | 与样式共享缓存相关的代码,这种优化允许类似节点共享样式而无需两次运行选择器匹配 |
str | 字符串相关的方法,用于 attribute 等类似的东东 |
style_adjuster | 一个结构,用于封装计算样式所需的所有样式修正和标记传播,以使其符合 CSS 规范 |
style_resolver | 给定元素或伪元素的样式解析 |
stylesheet_set | 一组集中的文档样式表 |
stylesheets | 样式表及其 CSS 规则 |
stylist | 选择器匹配 |
thread_state | 支持动态断言,关于什么类型的线程正在运行以及它处于什么状态 |
timer | 定时器模块,用于定义由脚本控制的 Timer 类型 |
traversal | 遍历 DOM 树;bloom 过滤器 |
traversal_flags | 控制遍历过程的标志 |
values | CSS 中用到的常用值-values |
文档的状态码的说明,详细见 #18 术语
诸如ED
,FPWD
,WD
,CR
,PR
,REC
等
ways to keep up to date with new publications
want to help
JSON.stringify()
JSON.parse()
以 MAC 为例:
brew install python
安装的 python,则会自动安装 pippython --version
是电脑里默认的 python 版本python3 --version
则是直接调用 python3pip3 --version
则是直接调用与 python3 匹配的包管理 pipbrew install automake pkg-config python cmake yasm
pip3 install virtualenv
,或者需要加选项 --user
./mach build --dev
0:38:02./mach build --release
0:42:16virtualenv 能创建一个隔绝的 python 环境(新的文件夹),里面包含所有必要的可执行文件,诸如对应的 Python 和 pip 等。
e.g.
# 1. 安装 homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
# 2. 安装 Python 和 pip
brew install python # Homebrew 会安装 pip3, pip3 是 Homebrew 版 Python 3 的 pip 的别名
python3 --version # Python 3.5.2
pip3 --version # pip 18.0 from /usr/local/lib/python3.7/site-packages/pip (python 3.7)
# 4. 安装 virtualenv
pip3 install virtualenv
virtualenv --version # 16.0.0
# 安装 proxychains-ng
brew install proxychains-ng # pywb 要用代理模式
# run with proxychains4,
e.g. Python
python # 将打开 python 解释器
python2 # python2 解释器
python3 # python3 解释器
python --version
python3 --version
e.g. virtualenv
virtualenv -p python3 venv # 指定python的版本,用virtualenv创建一个虚拟环境,虚拟环境的名字是“venv”,会创建一个文件夹,包含了python的可执行文件+pip库的拷贝,这样就随便安装其它包了)
source venv/bin/activate # 激活虚拟环境
pip3 install git+https://github.com/ikreymer/pywb.git
# 4.1 为工程创建一个虚拟环境
cd my_project_folder
virtualenv my_project # 会在当前的目录中创建一个文件夹
# 包含了Python可执行文件,以及 pip 库的一份拷贝,这样就能安装其他包了。
# 虚拟环境的名字(my_project)可以是任意的,若省略则会将文件均放在当前目录
# or
virtualenv -p /usr/bin/python2.7 my_project # 指定python解释器
# 4.2 开始使用虚拟环境,需要先被激活
source my_project/bin/activate
# 4.3 停用虚拟环境,如果您在虚拟环境中暂时完成了工作
$ deactivate # 这将会回到系统默认的Python解释器,包括已安装的库也会回到默认的。
rm -rf my_project # 要删除一个虚拟环境,只需删除它的文件夹
# 然后过了一段时间,你可能会有很多个虚拟环境散落在系统各处,有可能已经忘了它们的名字/位置
# 还有其它工具,方便你管理虚拟环境。略。
e.g. Rust 的 Hello world
## cargo 和 rust 语言及其编译器 rustc 本身的各种特性紧密结合
## 基本上 rust 开发管理中所需的手段,cargo 都有
$ cargo new hello_world --bin
# 使用 cargo new 在当前目录下新建了基于 cargo 管理的 rust 项目
# 项目名称为 hello_world
# --bin 表示该项目将生成可执行文件
$ cd hello_world
$ tree . # 瞄眼目录结构
$ cargo build # cargo 自动构建好全部
$ cargo run # 运行
$ cargo clean # 清理 target 文件夹
$ cargo update # 根据 toml 描述文件重新检索并更新各种依赖项的信息,并写入 lock 文件
$ cargo install # 实际的生产部署
## 两个核心文件:
## cargo.homl 项目数据描述文件,直接面向rust开发人员,决定了项目如何构建、测试、运行
## cargo.lock 项目依赖详细清单文件,一般不管
今年,我有幸参加了 2018 年的 TPAC 大会。第一次参会,感触颇多。
所以,想在这里分享一些信息,希望对大家有所帮助。
目录:
TPAC,全称 W3C Combined Technical Plenary / Advisory Committee Meetings Week,是 W3C 的年度重要技术会议之一。届时,W3C 的技术架构组(Technical Architecture Group,TAG)、顾问委员会理事会(Advisory Board,AB)、会员代表组成的顾问委员会(Advisory Committee,AC)、W3C 各技术小组以及公众邀请专家等,将进行为期五天的紧密合作,共同商讨未来 Web 的技术方向,深入讨论 W3C 的组织策略(摘自 W3C**)。
这里,我们划三个关键词:W3C、参会人员、年度技术大会。
W3C(World Wide Web Consortium,万维网联盟)旨在制定开放的 Web 标准,确保 Web 的长期发展。目前共有 1161 个 Web 标准和草案,包括WD
CR
PR
PER
REC
ret
Note
这 7 种。
WD
Working Draft 工作草案 ✔
- 不稳定也不完整。目的是创建当前规范的一个快照,也能征求 W3C 和公众的意见
CR
Candidate Recommendation 候选推荐标准 ✔
- 所有的已知 issues 都被解决了,向 implementor 征集实现
- AC 正式审查,可能有三种结果:成为标准、返回工作组继续完善、废弃
- 此阶段的很有可能成为标准,且如有改动,则需给出改动原因
PR
Proposed Recommendation 提案推荐标准 ✔
- 从
CR
到PR
需要全面的 test suite 和实现报告,以证明每个特性都在至少2款浏览器里实现了- 意味着其质量足以成为
REC
。此时,W3C 成员再最后一次 review 下规范
- 一般不会有实质性的改动;若有,则只能再发布一个新的
WD
或CR
PER
Proposed Edited Recommendation 已修订的提案推荐标准REC
Recommendation 推荐标准,通常称之为 standard,即事实标准 ✔
- 此时,就不会有太多变动了,当然依然可以收勘误
- 它可能成为
- Edited Recommendation 编辑推荐标准。微小改动,然后生成推荐的 Revised Edition
- Amended Recommendation 修订推荐标准。不增加新功能的实质性更改
SPSD
Superseded Recommendation 被取代的推荐标准(缺少足够的市场相关性)ret
Retired 退役的Note
Group Note 工作组说明
- 不打算成为标准的文档。已经停止使用了
- 通常记录规范以外的信息,eg.规范的用例及其最佳实践、解释规范被弃用的原因
W3C 是一个国际社区,它没有单一的物理总部,而是由四个机构共同主持的。分别是:美国的麻省理工学院、法国的 ERCIM、日本的庆应义塾大学、**的北京航空航天大学。这四个 Host 里的成员,即 W3C 员工,目前共 62 个人。
此外,W3C 还在世界各地设有 19 个 W3C Offices;它也积极和企业进行合作,截至 2018 年 11 月 4 日,W3C 有 475 个会员单位。
其中,**有 18+ 家会员单位,包括 360、阿里、百度、腾讯、华为、**移动、白鹭科技、遨游、21CN、北京知道创宇、北京文因互联、博彦集智、**信通院、**电子科技集团公司信息科学研究院、**电子标准化研究所、中科院、西南科技大学、浙江大学等。
符合以下条件之一的,便可参加 TPAC:
TAG
或AB
成员
TAG
Technical Architecture Group 技术架构组AB
Advisory Board 顾问委员会理事会AC
代表
AC
Advisory Committee 会员代表组成的顾问委员会WG
Working Group 工作组IG
Interest Group 兴趣组BG
Business Group 商务组CG
Community Group 社区组从 2010 年开始,TPAC 已经过了 9 个年头。
更多信息,可查看 W3C/TPAC
TPAC 期间将举行小组会议、AC 会议,以及技术开放日。其中,技术开放日采取分组开放讨论的形式,讨论与 W3C 未来技术相关的话题,对公众及所有参会者开放,其会议纪要也对外公开。顾问委员会会议及小组会议通常仅对 W3C 会员和特邀专家开放。TPAC 给参与的各方提供了一次面对面讨论的机会,这是非常难得的。
下表是 2018 年 TPAC 的行程安排。
周一 | 周二 | 周三 | 周四 | 周五 | |
---|---|---|---|---|---|
7:00-8:30 | ChairsBreakfast | ||||
8:00-8:30 | 注册 | 注册 | 注册 | 注册 | 注册 |
8:30-18:00 | WG 17个 |
WG 17个 |
技术开放日 | WG 19个 |
WG 18个 |
15:00-18:00 | AC会议 | AC会议 | |||
8:30-17:30 | CG 4个 |
CG 4个 |
CG 4个 |
CG 3个 |
|
晚上 | 开发者见面会 18:30-22:30 |
AC晚宴 19:00-21:30 |
TP招待会 18:30-21:00 |
- 小组会议,Group Meetings
WG
Working Group 工作组CG
Community Group 社区组- AC 会议,Advisory Committee Meeting,顾问委员会会议
- 技术开放日,Technical Plenary Day,
TP
Chairs-Breakfast 是 TPAC 主席们的早餐时间,也是一次非正式会议,边吃边聊。项目负责人用大约 5 分钟的时间介绍下项目概况及最新进展。
注册。之前已经在线注册过的,在前台根据护照/ID换取胸卡即可。TPAC 也支持现场注册。
小组会议,包括WG
(工作组)和CG
(社区组)。是在周一、周二、周四、周五这四天里举行的,详情可参阅 TPAC 2018 时间表(点击某个工作组的标题,则可看到它详细的议题列表)。我是参加了 CSS 和 Houdini 的小组会议,这在后面会介绍。
AC 会议是在周二和周四举行的,仅限 AC 代表或其委托人参加。
周一晚上的开发者见面会,有 12 个主题的 Demo 演示,展示了正在进行中的和还在探索中的标准化工作,包括 CSS Houdini、WebAuth、WebAudio、VR/AR、WoT、网络支付、WebML、WebVMT 等,可去 Demo 演示 页面查看主题详情。之后,有五个小演讲,分别是关于 CSS 新布局、Web 隐私、MDN 与 Web 标准、CSS 工作组和 Web 国际化的,感兴趣的朋友可以去页面 W3C开发者见面会 查看相应的介绍和在线 PPT。
周三的技术开放日,上午是 Jeff Jaffe 的欢迎致辞、TAG 组的介绍及公开答疑;中午和下午是话题分组讨论,共有 13*4-2=50 个话题,你可以挑选自己感兴趣的四个进行参与。当天的在线 PPT、议题列表及对应的会议纪要都在 TPAC 2018 Wiki 里列出来了,感兴趣的小伙伴可自取。
分组讨论的话题里,有两个来自**企业:
据说快应用的“现场讨论非常激烈,并且在 Google 负责 PWA 的 Alex Russell 也对快应用非常感兴趣” 摘自彭星的《小程序应和Web一样开放 | W3C TPAC Lyon 2018 参会感悟》
CSS 工作组的小组会议是在周一和周二进行的,共有 47+ 个话题。会议纪要可以在线查看,如下。
周一.会议纪要 | 周二.会议纪要 |
---|---|
进入会议纪要页面,点击你感兴趣话题,便可定位到彼时的讨论细节。值得一提的是,在纪要里一般都会给出对应的 Github 地址。点开 Github 地址便可看到关于此话题的来龙去脉,包括背景、要解决的问题、对应的规范以及在线讨论等非常有价值的信息,而且线下讨论的内容也会同步在评论区。非常推荐大家去 Github 上 w3c/csswg-drafts 垂直跟进自己感兴趣的 CSS 特性。
这里,我想和大家分享五个有意思的案例。
Spatial Navigation,空间导航。是在 Web 页面上使用方向键,根据元素的显示位置来进行导航。它是在 TPAC 2017 的技术开放日那天第一次和大家见面的,是 LG 的工程师将一个特定于电视领域的问题抽象出来,扩展在了 Web 上,详细的会议纪要见 2017/11/08-spatnav-irc。在之后的一年里,LG 的 Web 研究员 Jihye Hong 和 W3C 的特邀专家 Florian Rivoal 共同起草了这份编辑草案,并带着相应的 Web Polyfill 再一次来到了 TPAC 2018。本次会议上已将此规范纳入了 CSS WG ED
,并会向FPWD
推进。
ED
Editors' Draft 编辑草案(不是 W3C 技术报告/规范)FPWD
First Public Working Draft 首个公开工作草案Web 上的现有导航策略是,根据元素的
tabindex
属性或在 HTML 代码里的位置(无tabindex
时),按 Tab 键来导航。不得不说,在无鼠标操作的场景下,Spatial Navigation 还是很有优势的。
Constructable Stylesheet Objects,可构造的样式表对象。它定义了 CSSOM 的附加功能,使 StyleSheet 对象可以直接构造,也提供了在自定义元素中方便操作样式表的 API。它解决的是 Web 组件操作 Shadow DOM 样式的性能问题。
Aspect Ratio,宽高比。目的是让图片有良好的响应性。本次提议是增加一个 CSS 属性 aspect-ratio
,让它来控制图片的宽高比。之前还有个提议是给替换元素设置一个 intrinsic size,是考虑到替换元素自带宽高比信息。在此会议上,对该问题尚未给出最终解决方案。如果你有什么想法,欢迎去 Issues.Aspect Ratio 留言。
CSS Environment Variables,CSS 环境变量。在开会之前,我是第一次见这个特性,于是便简单地调研了下什么是 CSS 环境变量,结果发现它最初想要解决的竟然是 iPhone 的“刘海”问题,然后就不禁疑惑:这特定浏览器下的问题,也能提成 Web 规范?针对是否要将此草案升级为FPWD
的问题,大家进行了激烈的讨论。最后,综合各方意见,结论是升为FPWD
。
有个有说服力的观点:虽然问题是产生于特定浏览器,但场景是通用的,规范应该推动这类特性的发展
Scroll Linked Animations,滚动链接动画。该提案目前是在 WICG 里的。它定义了一种纯 CSS 写法,可以控制滚动类动画,实现的功能如 demos 所示。本次的诉求是将此规范从 WICG 移到 CSS WG。会议中,特邀专家 fantasai 确定后续会 review 此规范,且浏览器厂商们均对此提案表达了兴趣。相信此特性在后续的推进上,会比较流畅。想想用纯 CSS 就可以实现视差滚动了,有没有很兴奋?
demos 需要在 Chrome Canary 里运行,因为它目前是用 Animation Worklet 模拟的。Animation Worklet 是 Houdini 的一部分,感兴趣的小伙伴,请移驾下节。
Houdini 的小组会议是在周四进行的,议程安排见 TPAC 2018 F2F,会议纪要见 2018-10-25。
从规范的整体进度上看,有这两处改动:
FPWD
至此,CSS Houdini 的相关规范及其最新进度如下:
规范 | 进度 | 说明 | |
---|---|---|---|
1 | CSS Painting API 1 | CR |
用JS自定义CSS图像类型 |
2 | CSS Layout API Level 1 | FPWD |
用JS自定义布局 |
3 | CSS Animation Worklet 1 | FPWD |
可控制一组动画效果的脚本动画 |
4 | CSS Typed OM 1 | WD |
将CSSOM的值的字符串转成JS对象,性能好点 |
5 | CSS Properties and Values API 1 | WD |
注册新的CSS属性,可定义类型/继承/赋初始值 |
Font Metrics API | 提供基本的字体指标 | ||
CSS Parser API | 提供CSS解析的API |
最后,再分享两个有用的链接:
WICG,全称 Web Incubator Community Group,Web 孵化器社区组。它提供了一个轻量场所,方便开发人员提出 Web 新特性、新提议,也方便大家在 Github 上公开讨论。当提案变稳定和成熟了之后,就会考虑迁移到 W3C 工作组。
所以,对 Web 特性有新提议或者想关注新特性的小伙伴,就去逛 WICG 吧。
要将草案提交到 WICG,须至少有一个浏览器厂商对此 API 有兴趣
关于 W3C 的规范和标准。身为前端开发人员,当遇到一个新出炉的 Web 特性时,很多人难免会问“浏览器支持度如何?”。这完全能够理解。但在这里,我想说,就技术层面,浏览器厂商之间还是很有爱的。如果一个特性深受广大开发者的喜爱,大家都乐意实现它。
所以,下次当你发现一个好玩/有趣/有价值/有意义的 Web 新特性时,在感叹完“浏览器兼容性”之后,不要犹豫,就去 github.com/w3c 上表达你的喜爱吧~!有用的 Web 特性,让更多的人知道它的价值,是你的义务,更是你的权利。
Web 的持续发展,离不开每一个人的意见和建议。
经过这五天的面对面会议,深感我们还能做更多。我们,也要做更多。
最后,感谢 360 公司、奇舞团、360 搜索、360 导航对 360 W3C 工作组 的大力支持。
图为来到 TPAC 现场的 CSS 工作组成员。拍摄于法国里昂,2018.10.23
intrinsic dimensions 是指 intrinsic height, intrinsic width 和 intrinsic aspect ratio(宽高比)的集合。对于特定对象,每个都是有可能存在,也可能不存在。intrinsic dimensions 代表物体本身的 preferred 或者 natural size,它与上下文无关。CSS 没有定义如何找出 intrinsic dimensions。
举例:
<iframe>
元素如果一个对象(比如 icon)有多个 sizes,则将最大的 size(按面积)作为它的 intrinsic size。如果在那个 size 上它有多个 aspect ratios,或者有多个 aspect ratios 但是没 size,则就使用最接近 default object size 的 aspect ratio 的 aspect ratio。通过使用 contain constraint(包含约束)fit 来看哪一个 aspect ratio 在 default object size 里 fitting 后的面积最大;如果最大面积有多个 sizes,那就选 the widest size 作为它的 intrinsic size。
一个对象的 specified size 是由 CSS 指定的,比如通过 width, height, 或者 background-size 属性。
specified size 可以是确定的 width 和 height,可以是一组约束,也可以是它们的组合。
default object size 是一个具有确定 height 和 width 的矩形,用来在既没有 intrinsic dimensions 也没有 specified size 的时候,确定 concrete object size 的。
concrete object size 是综合对象的 intrinsic dimensions、specified size 以及 default object size,从而生成一个有明确 width 和 height 的矩形。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
https://drafts.csswg.org/css-images-3
此模块定义了 CSS3 里与<image>
type 和一些 replaced elements 相关的特性。
在 CSS1/CSS2 里,image values 只能是 url value
<image>
type 的值,可以用在 background-image, cursor, list-style-image, content 等属性上
此模块里定义的属性,只有
image-rendering
能用在::first-line
和::first-letter
目录:
<image>
Type: 2D Image Valuesglutin
窗口库的实现./mach build --debug
生成的东东./mach doc
时,由 rustdoc
工具生成的文档./mach build --release
生成的东东https://github.com/servo/servo/blob/master/docs/ORGANIZATION.md
CSS Animation Worklet API 是 CSS Houdini 的一部分。关于 Houdini 的介绍,可查看 #23。
这个 API 扩展了 Web 动画堆栈。具体来说:
举几个例子,大家来感受下什么是 有状态 的动画。
比如 Chrome 的顶部地址栏(点此链接查看动画效果),它的显隐不仅取决于滚动位置,还取决于滚动方向。i.e. 当上拉页面向下滚动时,它就隐藏了;当下拉页面向上滚动时,它又回来了,且不管是否有没有滚动到页面的顶部。
比如视差滚动,目前在 Web 上实现不太容易,详见 Performant Parallaxing。
比如自定义滚动条样式,让猫作为滚动条,要么需要我们自己监听滚动事件,然后还要确保动画流畅又不耗性能;要么实现起来不容易。
有了 Animation Worklet API,我们就可以非常直接且简单地控制此类动画效果了。
https://developers.google.com/web/updates/2018/10/animation-worklet
TPAC:W3C Combined Technical Plenary / Advisory Committee Meetings Week
参与人员:
TAG
Technical Architecture Group 技术架构组AB
Advisory Board 理事会AC
Advisory Committee 会员代表组成的顾问委员会WG
Working Group 工作组IG
Interest Group 兴趣组BG
Business Group 商务组CG
Community Group 社区组会议安排:5天 10.22-26
每天的详细安排,见官网,点击相应的工作组标题,可查看详情(内含议题)。
时间表如下:
周一.22 | 周二.23 | 周三.24 | 周四.25 | 周五.26 | |
---|---|---|---|---|---|
8:00-8:30 | Chairs Breakfast 7:00-8:30 | ||||
8:30-18:00WG |
WG 17个 |
WG 17个 |
TP Day & Breakout | WG 19个 |
WG 18个 |
CSS | CSS | Houdini Performance WoT |
Performance WoT |
||
15:00-18:00AC |
AC Meeting | AC Meeting | |||
8:30-17:30CG |
CG 4个 |
CG 4个 |
CG 4个 |
CG 3个 |
|
Meetup 18:30-22:30 | AC Dinner 19:00-21:30 |
TP Reception 18:30-21:00 |
旁听周五的 Automotive WG
WG
Working Group Meetings
CG
Community Group
Meetup
W3C Developer Meetup
TP
Technical Plenary Day
http://www.chinaw3c.org/TPAC2018-Overview.html
https://www.w3.org/2018/10/TPAC
https://www.w3.org/2018/10/TPAC/schedule.html
WG
在 Cité Centre de Congrès de Lyon
今天和大家分享一个非常酷炫的 API CSS Painting API。它是 CSS Houdini #23 的一部分。
它能做什么呢?简单点说,它可以让网页开发人员干预浏览器的绘制(Paint)环节。
为什么要干预绘制环节呢?干预绘制,意味着开发人员可以自行决定页面要绘制成的样子,而不一定非要等到浏览器支持才行。
举个例子,CSS3 的新属性conic-gradient
圆锥形渐变:
<style>
div {
display: inline-block;
width: 150px; height: 150px; margin: 10px;
border-radius: 50%;
}
.color-palette {
background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
}
.color-rgb {
border: 1px solid #999;
background: conic-gradient(red 0, red 16%,white 16%, white 32%,green 32%, green 48%,white 48%, white 64%,blue 64%, blue 80%,white 80%, white);
}
</style>
<div class="color-palette"></div>
<div class="color-rgb"></div>
以上代码的运行效果如下,也可在线预览(Chrome 69+):
根据 Can I use,目前仅 Chrome 支持conic-gradient
。但是,有了CSS Painting API
,我们就可以自己画出类似效果,然后在项目中使用了,而不用等到所有的浏览器都支持conic-gradient
。
当然,除了充当 CSS3 新特性的 polyfill 之外,我们还可以用它画任意形状。比如钻石状的 Div:
比如,符合 Google Material Design 的波纹效果:
截止目前,CSS Painting API 的浏览器支持情况如下:
也有相应的 CSS Paint Polyfill 供我们选择。
CSS Painting API Level 1 已于今年8月9日成为候选推荐标准,这意味着该模块的所有已知 Issues 均已被解决,并且已经开始向浏览器厂商征集实现。
Webrecorder pywb 是 python 的一个功能完备的、高级 web 归档捕获和重播框架。它提供了命令行工具,高保真 Web 存档访问。版本 2.0
pywb 是功能完备的 web archive replay 系统,也叫 wayback machine,提供 replay, view, archived。
pywb 有很多命令行,先来看两个入门的
想要创建一个 WARC 文件,可查看 Creating a Web Archive
安装了 pywb tool-suite 之后,就能用下面的 command-line apps 了。所有的 serve 工具都有不同的默认端口,当然你也可以覆盖它。
cdx-indexer
cdx-indexer -h
可以查看所有的 optionswb-manager
wb-manager init <coll>
wb-manager add <coll> <warc>
matadata.yaml
wb-manager -h
warcserver
config.yaml
里的所有 collectionswayback (pywb)
wayback
application 被安装 (pywb是同样的application,以后可能就都用它了)config.yaml
live-rewrite-server
wayback
的快捷方式(shorcut), 但是只要 Live Web Collectionpywb 提供了一种可扩展的 YAML , 基于配置格式,通过 config.yaml
, 在每一个 web archive 的根目录。
https://pywb.readthedocs.io/en/latest/manual/configuring.html#configuring-pywb
在没有客户端URL重写的情况下,提供可能更好的重放。 通过 --proxy,即 wayback --proxy my-web-archive
sudo pip3 install pywb --user
## 1. 运行已经存在的
wayback --proxy WBEZ --port 8321
proxychains4 /Users/anjia/quantum/servo/mach run -r --certificate-path proxy-certs/pywb-ca.pem https://www.wbez.org/
## 2. 录制自己的
wb-manager init 360
wayback --proxy 360 --live --proxy-record --autoindex --port 8321
proxychains4 /Users/anjia/quantum/servo/mach run -r --certificate-path proxy-certs/pywb-ca.pem http://localhost:8321/360/record/https://www.360.cn/
proxychains4 /Users/anjia/quantum/servo/mach run -r --certificate-path proxy-certs/pywb-ca.pem https://www.360.cn/
## 3. 测试
wayback --proxy 360 --port 8321
proxychains4 /Users/anjia/quantum/servo/mach run -r --certificate-path proxy-certs/pywb-ca.pem https://www.360.cn/
e.g.
# 运行一个已存在的 archive
wayback --proxy WBEZ --port 8321
# WEBZ 是一个已经存在的文件夹,也称为 Collection
# --port 8321 是配置的端口,在 proxychains.conf 里
## 就可以配置浏览器 Proxy Settings 到特定的端口了,再加载特定的 url,就会加载最新的 archive copy 了
wayback --proxy my-web-archive # 启动pywb,开启代理模式访问
proxychains4 ${SERVO_DIRECTORY}/mach run -r --certificate-path proxy-certs/pywb-ca.pem https://www.wbez.org/
proxychains4 ./mach run -r --certificate-path proxy-certs/pywb-ca.pem https://www.wbez.org/
## other
wayback --record --live -a --auto-interval 10 #
http://localhost:8321/360/record/https://www.360.cn/ # 在浏览器中访问
Vue-Socket.io 是一个 Vuejs 的 socket.io 集成。
介绍如何编译、运行、调试 Servo 环境
setup environment to compile, run, debug
./mach build -d
./mach build -r
target/debug/servo
和target/release/servo
目录下./mach
./mach run -d -- http://github.com
等价于./target/debug/servo http://github.com
./mach
mach
是一个 python 的 utility
mach
完成的./mach --help
./mach run -d [mach options] -- [servo options]
--
把 mach options 和 servo options 分开
./mach --help
./mach run -- --help
println!
如何工作,尤其是 formatting traitsCargo.toml
这些文件里Cargo.toml
每个文件夹下都有自己的依赖项Cargo.lock
依赖项的特定版本cargo update -p std_image
./mach cargo-update -p std_image
[replace]
./mach run -d -- --help
./mach run -d -- --debug help
以上仅为快照,更多详情见 Hacking Quickstart
document.cookie
credentials: "include"
或 withCredentials: true
前端路由和数据接口,均配置 host
function escapeRe(str) {
return str.replace(/[.*+?^$|[\](){}\\-]/g, '\\$&');
}
// Get the cookie value by key.
function get(key, decoder = decodeURIComponent) {
if ((typeof key !== 'string') || !key) {
return null;
}
const reKey = new RegExp(`(?:^|; )${escapeRe(key)}(?:=([^;]*))?(?:;|$)`);
const match = reKey.exec(document.cookie);
if (match === null) {
return null;
}
return typeof decoder === 'function' ? decoder(match[1]) : match[1];
}
export default {
get: get
}
渐变(Gradient)是 CSS3 引入的特性,其定义详见 CSS Images Module Level 3。它本质上是一个 2D 图像,可以对 background-image、list-style-image 和 border 等进行细微着色。
语法是:
<gradient> = <linear-gradient()> | <repeating-linear-gradient()> |
<radial-gradient()> | <repeating-radial-gradient()> |
<conic-gradient()> | <repeating-conic-gradient()>
渐变会绘制到一个叫渐变框(gradient box)的矩形框里。渐变框有具体的大小,而渐变本身是没有固有尺寸的。
固有尺寸(intrinsic dimensions)是固有宽度、固有高度、固有宽高比的集合。对于特定的对象,这三个尺寸都有可能存在或者不存在。比如:光栅图像(image)同时拥有这三个,SVG image 只有一个固有宽高比,CSS 渐变就没有任何固有尺寸。
举个例子,理解下。
在下面的代码中,渐变框就是.demo
容器的 padding box,宽 220px 高 120px。
<style>
.demo {
width: 200px;
height: 100px;
padding: 10px;
background-color: #eaeaea;
background-image: linear-gradient(red, green); /* 线性渐变 */
background-repeat: no-repeat;
background-position: center;
}
</style>
<div class="demo"></div>
如果你给 .demo
再增加一行下面的 CSS,那么,渐变框就变成了宽 50px 高 50px。
.demo {
background-size: 50px 50px;
}
如果你是增加的下面这行 CSS,那么,渐变框就变成了宽 440px 高 240px。
.demo {
background-size: 200% 200%;
}
同一个渐变,在渐变框大小不同时呈现的不同效果:
220px * 120px | 50px * 50px | 440px * 240px |
---|---|---|
理解 1. 渐变本身是没有固有尺寸的,虽然渐变框有具体大小
要想指定一个渐变效果,只需定义这三个元素,即可:
这样,颜色就会平滑地填充渐变线上的其余部分。
不同的渐变类型,会定义如何使用渐变线上的颜色们来生成实际的渐变。
渐变类型,在几何上,可以是:
- 线段(line):对应 CSS 的线性渐变(linear gradient)
- 射线(ray):对应 CSS 的径向渐变(radial gradient)
- 螺旋(spiral):对应 CSS 的圆锥渐变(conic gradient)
理解 2. 渐变三元素:渐变线、起始点和结束点、颜色序列
目录
- Quantum 初探:即本篇文章,将介绍 Quantum 项目的由来和概况,引出它的强大“后台” Servo
- Servo 的设计架构:介绍了 Servo 的基于任务的设计架构,重点介绍了并行并发的策略
quantum 这个词来自拉丁语 quantus,意思是 how great - 多么伟大
Quantum 是 Mozilla 为了构建下一代 Web 引擎的项目。在正式介绍它之前,我们需要先了解一些浏览器的相关知识。
图1. 浏览器结构,源自 How Browsers Work
渲染引擎(Rendering Engine)也叫布局引擎(Layout Engine)。浏览器的渲染引擎,有时也简称为浏览器引擎(Browser Engine)。
注意:这里的 Browser Engine 不同于图1中的 Browser engine
所以,以下名词往往是等价的:
浏览器的渲染引擎 ~ 浏览器引擎 ~ 渲染引擎 ~ 布局引擎
主流浏览器用到的渲染引擎如下:
浏览器 | 渲染引擎(开发语言) | 脚本引擎(开发语言) |
---|---|---|
Chrome | Blink (c++) | V8 (c++) |
Opera | Blink (c++) | V8 (c++) |
Safari | WebKit (c++) | JavaScript Core (nitro) |
FireFox | Gecko (c++) | SpiderMonkey (c/c++) |
Edge | EdgeHTML (c++) | Chakra JavaScript Engine (c++) |
IE | Trident (c++) | Chakra JScript Engine (c++) |
之所以列出“脚本引擎”,旨在强调渲染引擎不负责 JS。对 JS 的解释和执行是由独立的引擎完成的,比如大名鼎鼎的 V8 引擎。
对 HTML 文档来说,渲染引擎的主要任务就是解析 HTML 和 CSS,再把最终的结果绘制到屏幕上。
下面是各个渲染引擎的时间线,我们可以很直观地看出她们的生日和年龄。其中,Trident、KHTML、Presto 已经停止更新;Gecko、WebKit、Blink 和 Edge 依然在持续更新中。
图2. 浏览器引擎,源自维基百科 Browser engine
2013年,Mozilla 启动了一项研究型项目 Servo。这是一个从零开始设计的浏览器引擎,目标是提高并发性和并行性,同时减少内存安全漏洞。它是由 Rust 语言编写的,而 Rust 有更好的内存安全属性和并发功能。
2016年4月,考虑到 Servo 还需要几年才能成为功能完备的浏览器引擎。所以,Mozilla 决定启动 Quantum 项目,将 Servo 的稳定部分带到 Firefox 里。
关于集成到 Firefox 中的 Servo 组件,可查看 Jack Moffitt 的演讲视频 Web Engines Hackfest
Gecko 是 Mozilla 的一个成熟且功能健全的 Web 浏览器引擎,它起源于1997年的 Netscape。Mozilla 采用渐进式的方法,将 Servo 里已稳定的组件迁移到 Gecko 中,用户将不必等很长时间就能看到 Firefox 在稳定性和性能上的显著改进。
2017年11月发布的 Firefox 57 是第一版启用了 Servo 组件的浏览器,之后便在此版本的基础上进行迭代开发。
Quantum 以 Gecko 引擎为基础,同时利用了 Rust 的良好并发性和 Servo 的高性能组件,为 Firefox 带来了更多的并行化和 GPU 运算,让 Firefox 更快更可靠。
Quantum 是一个将 Mozilla 的多个社区及其代码仓库联系在一起的大项目,它包含多个子项目:
至此,大家对 Quantum 项目的由来和概况有了初步的认识。后续,我会继续探索更多详细内容。敬请期待。
HTTP,Hypertext Transter Protocol,超文本传输协议。
Transfer 翻译成了“传输”
Transfer 是表示“(状态的)转移”,依据 HTTP 制定者之一的博士论文
它有很多应用,但最著名的是用于 Web 浏览器和 Web 服务器之间的双工通信。
在这本书中,我们会:
目标读者:
本书:
本书共 21 个章节,分为5 个逻辑部分,每个部分都是一个技术专题。
包含参考资料、相关技术介绍
《HTTP权威指南》 读书笔记
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
返回:新的字符串数组
for-in
const arr = ['an', 'jia', 'zora'];
console.log(Object.keys(arr)); // ["0", "1", "2"]
const obj = {
0: 'an',
1: 'jia',
2: 'zora'
};
console.log(Object.keys(obj)); // ["0", "1", "2"]
const person = Object.create({}, {
// 是不可枚举的,所以不输出
getName: {
value: function() { return this.name; }
}
});
person.name = 'anjia';
console.log(Object.keys(person)); // ["name"]
// 基本数据类型
console.log(Object.keys('anjia')); // ["0", "1", "2", "3", "4"]
/**
* 说明:ES5会报错,ES2015会将非对象参数强制转换成对象
*/
Nginx 是 HTTP Server。常用来做:
它和 Tomcat 虽然都叫 web server,但二者有本质的不同。Tomcat 是 Application Server,常用来做应用容器,让 Java App 运行在其中。
HTTP Server 关心的是 HTTP 协议层面的传输和访问控制,所以 Nginx 有代理、负载均衡等功能。客户端通过 HTTP Server 访问服务器上存储的资源(HTML文件、图片文件等)。通过 CGI 技术,也可以将处理过的内容通过 HTTP Server 分发。但是,HTTP Server 始终只是把服务器上的文件,如实的通过 HTTP 协议传输给客户端。
而 Application Server,则是应用执行的容器。它首先需要支持开发语言的 Runtime(对于 Tomcat 而言,就是 Java),保证应用能正常运行。其次,需要支持应用相关的规范,比如类库、安全方面的特性(对于 Tomcat 就是要提供 JSP/Sevlet 运行需要的标准类库等)。为了方便,Application Server 也会集成 HTTP Server 的功能,但不如专业的 HTTP Server 那么强大。所以 Application Server 往往是运行在 HTTP Server 背后,执行应用,将动态内容转化为静态内容之后,通过 HTTP Server 分发到客户端。
Nginx 的优点是占用资源少。
在 Mac 下
brew install nginx
sudo brew services start nginx // 如果 http://localhost:8080 看到 Welcome to nginx! 页面,说明启动成功
sudo brew services stop nginx // 关闭 nginx 服务
sudo brew services reload nginx // 重新加载
nginx -v // 查看版本
nginx -s reload // 重新加载
nginx -s stop // 停止
sudo nginx -t // sudo
// nginx 会测试配置文件的语法,告诉你配置文件是否正确,同时也会给出配置文件的路径
ps aux | grep nginx
/..../nginx -t
SemVer: Semantic Version, 语义化版本
主版本号.次版本号.修订号
主版本号
:当你做了不兼容的 API 修改。 不兼容的大改动次版本号
:当你做了向下兼容的功能性新增。 功能性改动修订号
:当你做了向下兼容的问题修正。 bugfixx.y.z-alpha
内测版
x.y.z-beta
公测版
x.y.z-stable
稳定版
初始化开发版本 0.1.0
正式上线了一次,就 1.0.0
主版本号为0时,是为了做快速开发
Cargo 做了4件事情:
rustc
或其它构建工具cargo new hello_test --bin # --bin 意思是 binary,即二进制项目,比如库文件
cd hello_test
tree .
cargo build # 获取依赖及其子依赖,编译它们,更新 Cargo.lock
./target/debug/hello_test # hello_test 是个二进制文件
cargo run # 和以上2条命令等价。会自动检测-如果已编译过&文件未改变,则就不重新编译了
cargo build --release # 会放在文件夹 ./target/release 下
cargo check # 快速(检查)编译,但不生成可执行文件
cargo update # 更新所有依赖
cargo update -p rand # 仅更新"rand"依赖
eg.
Cargo.toml
描述项目的依赖Cargo.lock
由Cargo自动生成,不用手动修改
Cargo.lock
放在.gitignore
里Cargo.lock
放在git
的版本仓库里eg. 来自 crates.io
semver
语义的版本解析和比较semver-parser
解析semver规范rustc_version
查询已安装的rustc编译器版本libc
类型和绑定到本地C函数的库,通常是在libc或其他通用平台的库中eg. 生成的目录结构
Cargo.toml
和Cargo.lock
在项目的根目录src
放源码
src/lib.rs
默认的库文件src/main.rc
默认的可执行文件src/bin/*.rs
其它的可执行文件test
examples
benches
eg. 关于测试的
cargo test # 会寻找两个地方,每个`src`文件和`tests/`目录
cargo test foo # 将会运行名字里带有foo的所有测试
# 更多见 https://doc.rust-lang.org/book/testing.html
命令“cargo test”运行测试用例,寻找两个地方的:
src
文件,单元测试tests/
目录下的,集成测试
.travis.yml
.gitlab-ci.yml
eg.构建缓存
rustc
编译就不方便了cargo build # 开发-快速构建
cargo build --realease # 发布-快速运行
.toml
, Tom's Obvious, Minimal Language, 作者是 Tom Preston-Werner toml
CSS Layout API 能让网页开发人员写自己的布局算法。它是 CSS Houdini #23 的一部分
这样,我们在 CSS 里写display
属性值的时候,就不局限于浏览器已经支持的那几种布局了,诸如display: block
、display: flex
等,我们可以写display: layout(myLayout)
Layout API 里的所有内容都在 Logical Coordinate System(逻辑坐标系统)里计算。这样的话,网站的书写模式就可以自动影响到你写的布局了。
对于熟悉文本从左到右书写的开发人员来说,Logical Coordinate System 到我们日常用到的名词的对应关系如下:
Logical | 在CSS里写的 |
---|---|
inlineSize | width |
inlineStart | left |
inlineEnd | right |
blockSize | height |
blockStart | top |
blockEnd | bottom |
知道这个名词对应关系有什么意义呢?等会在编写 Layout Worklet 的时候,你会看到代码里大量用到了第一列的属性值。
参考 https://github.com/w3c/css-houdini-drafts/blob/master/css-layout-api/EXPLAINER.md
for
最古老的循环,效率高。处理大量循环的时for-of
只遍历对象上的,ES6forEach
数组内部的方法。稀疏数组for-in
会遍历继承链的对象属性。遍历对象的属性,仅可枚举类型map
产生新数组。数组的每项经过计算,产生的新值filter
产生新数组。返回 true 的值reduce
返回值。前项加后项,累计计算最终值every
布尔值。遇到返回 false 的,就返回 false。 检测每一项是否符合条件some
布尔值。遇到返回 true 的,就返回 true。 检查是否有符合条件的项for > for-of > forEach > filter > map > for-in
every > some
const arr = [1,2,3,4,5];
// const arr = [{'name': 'anjia', 'score': { 'math':90, 'eng':100}}, 5, 'test'];
function log(msg, prefix){
prefix ? console.log('\n' + msg) : console.log(msg);
}
log('for', true);
for(let i=0, len=arr.length; i<len; i++){
log(arr[i]);
}
log('for-of', true);
for(let item of arr){
log(item);
}
log('forEach', true);
arr.forEach(item => {
log(item);
});
log('for-in', true);
for(i in arr){ // 下标
log(arr[i]);
}
function log(msg, prefix){
prefix ? console.log('\n'+msg) : console.log(msg);
}
log('map', true);
var arr = [1,2,3,4,5];
var newArr = arr.map(item => {
log(item);
return item*2;
});
log(newArr);
log('filter', true);
var arr = [1,2,3,4,5,6];
let greater = arr.filter(item =>{
log(item);
return item > 3;
});
log(arr);
log(greater);
log('reduce', true);
let scores = [10, 20, 30];
let total = scores.reduce((sum, item)=>{
console.log('sum=', sum, ' item=', item);
return sum + item;
}, 0);
log(total);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.