你问的Svelte来了--静态编译、直出DOM、独立分发Web Components、位掩码变化追踪
作者:互联网
Svelte
Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。
上述是官方的介绍,提取关键词:
- 用户界面的方法:定位是UI框架。
- 编译阶段处理: Svelte 直接将模板编译成了原生 DOM,而 vue 等框架会将模板编译成虚拟DOM;浏览器支持原生 DOM 的渲染,无需运行时处理。
- 与使用虚拟(virtual)DOM 差异对比不同:直接编译成原生DOM,因此不具备基于 render function 的组件的强大抽象能力。
- 像做外科手术一样更新 DOM:采用一种 Bitmask-based change tracking 的机制配合赋值语句实现的。(这是本文介绍的重点)
Svelte 的核心在于通过静态编译减少框架运行时的代码量。
示例
App.svelte
<h1> {count}</h1>
<button on:click={handleClick}>加1</button>
<button on:click={resetClick}>重置</button>
<script>
let count = 0
function handleClick() {
count +=1
}
function resetClick () {
count = 0
}
</script>
<style>
button {
background-color: #fff;
}
</style>
js 编译后的结果
/* App.svelte generated by Svelte v3.38.2 */
import { SvelteComponent, ... } from "svelte/internal";
function create_fragment(ctx) {
let h1;
let t0;
let t1;
let button0;
let t3;
let button1;
let mounted;
let dispose;
return {
c() {
h1 = element("h1");
t0 = text(/*count*/ ctx[0]);
t1 = space();
button0 = element("button");
button0.textContent = "加1";
t3 = space();
button1 = element("button");
button1.textContent = "重置";
attr(button0, "class", "svelte-1328v8p");
attr(button1, "class", "svelte-1328v8p");
},
m(target, anchor) {
insert(target, h1, anchor);
append(h1, t0);
insert(target, t1, anchor);
insert(target, button0, anchor);
insert(target, t3, anchor);
insert(target, button1, anchor);
if (!mounted) {
dispose = [
listen(button0, "click", /*handleClick*/ ctx[1]),
listen(button1, "click", /*resetClick*/ ctx[2])
];
mounted = true;
}
},
p(ctx, [dirty]) {
if (dirty & /*count*/ 1) set_data(t0, /*count*/ ctx[0]);
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(h1);
if (detaching) detach(t1);
if (detaching) detach(button0);
if (detaching) detach(t3);
if (detaching) detach(button1);
mounted = false;
run_all(dispose);
}
};
}
function instance($$self, $$props, $$invalidate) {
let count = 0;
function handleClick() {
$$invalidate(0, count += 1);
}
function resetClick() {
$$invalidate(0, count = 0);
}
return [count, handleClick, resetClick];
}
class App extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, {});
}
}
export default App;
css编译结果
button.svelte-1328v8p{background-color:#fff}
简化一下js编译内容:
{
c() {}, // create
m() {}, // mount
p() {}, // update
i() {}, // intro
o() {}, // outro
d() {} // destroy
}
上述各个方法,包裹了对原生 DOM 操作的方法,所以在运行时浏览器可以直接执行。
核心
Svelte 和 vue 等框架最大的不同就是编译成原生 DOM,其意味着单组件可以迁移或者在其他任何前端框架下使用「可独立分发的 Web Components」(因为其不存在运行时构建及对一些标签的支持等问题,不需要每个组件都要复制一份框架),当然 vue 等框架也推出了一些单组件构建的工具。
构建 web 组件:
-
使用 Svelte 官方组件模板 创建组件
npx degit sveltejs/component-template my-hello
-
修改原文件
package.json
:name: 'MyHello'
- 文件名修改:
src\Component.svelte --> src\MyHello.svelte
(index.js
中同步修改引入地址) - rollup.config.js:
svelte( {customElement: true })
-
编写源文件
MyHello.svelte
<svelte:options tag="my-hello" /> <h1>Hello {name}</h1> <script> export let name </script> <style> h1 { color: bule; } </style>
-
生成 web 组件
yarn yarn build
-
验证,创建
test.html
,引入构建后内容<body> <script src="./dist/index.js"></script> <my-hello name="ligang"></my-hello> </body>
基于位掩码的变化追踪
基于位掩码的变化追踪(Bitmask-based change tracking)是 Svelte 处理响应的方案。
掩码
在计算机学中指的是一串二进制数字,通过与目标数字的按位操作,达到屏蔽指定位的目的。
位掩码
- 二进制:是由1和0两个数字组成的,它可以表示两种状态,即开和关。所有输入电脑的任何信息最终都要转化为二进制。
- 位运算:对二进制进行逻辑运算。程序中的所有数在计算机内存中都是以二进制的形式储存的。
运算符 | 用法 | 描述 |
---|---|---|
按位与 | a & b | 对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。 |
按位或 | a | b | 对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。 |
按位异或 | a ^ b | 对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。 |
按位非 | ~ a | 反转操作数的比特位,即0变成1,1变成0。 |
左移 | a << b | 将 a 的二进制形式向左移 b (< 32) 比特位,右边用0填充。 |
有符号右移 | a >> b | 将 a 的二进制表示向右移b (< 32) 位,丢弃被移出的位。 |
无符号右移 | a >>> b | 将 a 的二进制表示向右移b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。 |
老鼠试毒(经典例子)
有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,问至少要多少只小白鼠才能在24小时内鉴别出哪瓶水有毒?
答案:采用位掩码,
2
10
=
1024
2^{10}=1024
210=1024 ,最多 10 只。
s
t
a
t
e
s
x
>
=
b
u
c
k
t
e
t
s
x
>
=
log
s
t
a
t
e
s
b
u
c
k
e
t
s
x
>
=
l
o
g
(
b
u
c
k
t
e
t
s
)
l
o
g
(
s
t
a
t
e
s
)
states^x >= bucktets \\ x >= \log_{states} buckets \\ x >= \frac{log(bucktets)}{log(states)} \\
statesx>=bucktetsx>=logstatesbucketsx>=log(states)log(bucktets)
其中,
s
t
a
t
e
s
=
t
i
m
e
T
o
T
e
s
t
/
t
i
m
e
T
o
D
i
e
+
1
states = timeToTest / timeToDie + 1
states=timeToTest/timeToDie+1
(1000).toString(2) // "1111101000"
简化示例(有7瓶水),来说明执行过程:
水(第n瓶) | 3号位 | 2号位 | 1号位 |
---|---|---|---|
(第7瓶) | 1 | 1 | 1 |
(第6瓶) | 1 | 1 | 0 |
(第5瓶) | 1 | 0 | 1 |
(第4瓶) | 1 | 0 | 0 |
(第3瓶) | 0 | 1 | 1 |
(第2瓶) | 0 | 1 | 0 |
(第1瓶) | 0 | 0 | 1 |
第一只老鼠:喝掉1号位为1的水(0b1010101)
第二只老鼠:喝掉2号位为1的水(0b1100110)
第三只老鼠:喝掉3号位为1的水(0b1111000)
死亡(老鼠编号1、2、3) | 结论(第几瓶) |
---|---|
1 | 0b001 => 第1瓶 |
1、2 | 0b011 => 第3瓶 |
1、3 | 0b101 => 第5瓶 |
1、2、3 | 0b111 => 第7瓶 |
2 | 0b010 => 第2瓶 |
2、3 | 0b110 => 第6瓶 |
3 | 0b100 => 第4瓶 |
function poorMouse (buckets, timeToDie, timeToTest) {
let states = timeToTest / timeToDie + 1
let temp = Math.log(buckets) / Math.log(states)
return Math.ceil(temp)
}
svelte 中位掩码的使用:
变量 | 对应位 |
---|---|
a | 0b001 |
b | 0b010 |
c | 0b100 |
实际生产中的使用
8421 权限管理
const Get = 1
const Post = 2
const Put = 4
const Delete = 8
function resolvePremission (perm) {
return {
get: (perm & Get) === Get,
post: (perm & Post) === Post,
put: (perm & Put) === Put,
delete: (perm & Delete) === Delete
}
}
位运算可以确保最小的内存占用,但单个位掩码中包含的标志数量是有限的。在 JavaScript 中,所有数字变量默认都是32位有符号整数,其允许包含32个不同的标志。要超越次限制,就必须移动到另一个变量中去。
- 如果标志数量不会超过单个变量中允许的数量,则位掩码是一个很好的选择,以提高数据操作的效率并减少内存占用。
- 在单个变量中包含 32 个标志可以是减少管理 32 个不同变量的膨胀的好方法。尤其在 json 文件或 SQL 数据库中可能更重要。
标签:count,Web,Svelte,直出,DOM,let,掩码,svelte 来源: https://blog.csdn.net/ligang2585116/article/details/117930807