前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >你问的Svelte来了--静态编译、直出DOM、独立分发Web Components、位掩码变化追踪

你问的Svelte来了--静态编译、直出DOM、独立分发Web Components、位掩码变化追踪

作者头像
奋飛
发布2021-08-31 16:59:49
发布2021-08-31 16:59:49
1.2K00
代码可运行
举报
文章被收录于专栏:Super 前端Super 前端
运行总次数:0
代码可运行

Svelte

Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。

上述是官方的介绍,提取关键词:

  1. 用户界面的方法:定位是UI框架。
  2. 编译阶段处理: Svelte 直接将模板编译成了原生 DOM,而 vue 等框架会将模板编译成虚拟DOM;浏览器支持原生 DOM 的渲染,无需运行时处理。
  3. 与使用虚拟(virtual)DOM 差异对比不同:直接编译成原生DOM,因此不具备基于 render function 的组件的强大抽象能力。
  4. 像做外科手术一样更新 DOM:采用一种 Bitmask-based change tracking 的机制配合赋值语句实现的。(这是本文介绍的重点

Svelte 的核心在于通过静态编译减少框架运行时的代码量

示例

App.svelte

代码语言:javascript
代码运行次数:0
复制
<h1> {count}h1>
<button on:click={handleClick}>加1button>
<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 编译后的结果

代码语言:javascript
代码运行次数:0
复制
/* 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编译结果

代码语言:javascript
代码运行次数:0
复制
button.svelte-1328v8p{background-color:#fff}

简化一下js编译内容:

代码语言:javascript
代码运行次数:0
复制
{
	c() {},	// create
	m() {},	// mount
	p() {},	// update
	i() {},	// intro
	o() {},	// outro
	d() {}	// destroy
}

上述各个方法,包裹了对原生 DOM 操作的方法,所以在运行时浏览器可以直接执行。

核心

Svelte 和 vue 等框架最大的不同就是编译成原生 DOM,其意味着单组件可以迁移或者在其他任何前端框架下使用「可独立分发的 Web Components」(因为其不存在运行时构建及对一些标签的支持等问题,不需要每个组件都要复制一份框架),当然 vue 等框架也推出了一些单组件构建的工具。

构建 web 组件:

基于位掩码的变化追踪

基于位掩码的变化追踪(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>=logstates​bucketsx>=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

代码语言:javascript
代码运行次数:0
复制
(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瓶

代码语言:javascript
代码运行次数:0
复制
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 权限管理

代码语言:javascript
代码运行次数:0
复制
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 数据库中可能更重要。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/06/15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Svelte
    • 示例
    • 核心
  • 基于位掩码的变化追踪
    • 老鼠试毒(经典例子)
    • svelte 中位掩码的使用:
    • 实际生产中的使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档