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

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

作者:互联网

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

<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 组件:

  1. 使用 Svelte 官方组件模板 创建组件

    npx degit sveltejs/component-template my-hello
    
  2. 修改原文件

    • package.jsonname: 'MyHello'
    • 文件名修改:src\Component.svelte --> src\MyHello.svelteindex.js中同步修改引入地址)
    • rollup.config.js:svelte( {customElement: true })
  3. 编写源文件 MyHello.svelte

    <svelte:options tag="my-hello" />
    <h1>Hello {name}</h1>
    
    <script>
      export let name
    </script>
    
    <style>
      h1 {
        color: bule;
      }
    </style>
    
  4. 生成 web 组件

    yarn
    yarn build
    
  5. 验证,创建 test.html,引入构建后内容

    <body>
      <script src="./dist/index.js"></script>
      <my-hello name="ligang"></my-hello>
    </body>
    

在这里插入图片描述

基于位掩码的变化追踪

基于位掩码的变化追踪(Bitmask-based change tracking)是 Svelte 处理响应的方案。

掩码

在计算机学中指的是一串二进制数字,通过与目标数字的按位操作,达到屏蔽指定位的目的。

位掩码

运算符用法描述
按位与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

(1000).toString(2)    // "1111101000"

简化示例(有7瓶水),来说明执行过程:

水(第n瓶)3号位2号位1号位
(第7瓶)111
(第6瓶)110
(第5瓶)101
(第4瓶)100
(第3瓶)011
(第2瓶)010
(第1瓶)001

第一只老鼠:喝掉1号位为1的水(0b1010101)
第二只老鼠:喝掉2号位为1的水(0b1100110)
第三只老鼠:喝掉3号位为1的水(0b1111000)

死亡(老鼠编号1、2、3)结论(第几瓶)
10b001 => 第1瓶
1、20b011 => 第3瓶
1、30b101 => 第5瓶
1、2、30b111 => 第7瓶
20b010 => 第2瓶
2、30b110 => 第6瓶
30b100 => 第4瓶
function poorMouse (buckets, timeToDie, timeToTest) {
  let states = timeToTest / timeToDie + 1
  let temp = Math.log(buckets) / Math.log(states)
  return Math.ceil(temp)
}

svelte 中位掩码的使用:

在这里插入图片描述

变量对应位
a0b001
b0b010
c0b100

实际生产中的使用

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个不同的标志。要超越次限制,就必须移动到另一个变量中去。

标签:count,Web,Svelte,直出,DOM,let,掩码,svelte
来源: https://blog.csdn.net/ligang2585116/article/details/117930807