Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。与使用虚拟(virtual)DOM 差异对比不同。
<script>
let count = 0;
</script>
<input type=number bind:value={count}>
<button on:click="{() => count += 1}">count</button>
在 componet 中,包括 fragment、ctx 和 UI 均是由 Svelte
编译器编译而成的。
create_fragment
方法,是编译器根据 App
的 UI
编译而成,提供组件与浏览器交互的方法,在编译结果中,包含3个方法:
c
,代表create
,用于根据模版内容,创建对应DOM Element
。m
,代表mount
,用于将c
创建的DOM Element
插入页面,完成组件首次渲染。会调用insert
方法,而insert
方法内会调用target.insertBefore。
d
,代表detach
,用于将组件对应DOM Element
从页面中移除。detach
方法内会调用parentNode.removeChild。
其中c
、m
方法用于组件首次渲染。因为首次渲染 App
没有变化状态的逻辑,所以 p (update)不会出现在编译产物中。
每个组件对应一个继承自SvelteComponent
的class
,实例化时会调用init
方法完成组件初始化,create_fragment
会在init
中调用。
所以组件的编译结果包括以下三部分:
fragment
:编译为create_fragment
方法的返回值UI
:create_fragment
返回值中m
方法的执行结果ctx
:代表组件的上下文
Svelte
编译器会追踪<script>
内所有变量声明:
- 是否包含改变该变量的语句;
- 是否包含重新赋值的语句。
若有,会将该变量提取到 instance
方法中,instance
执行后的返回值就是组件对应ctx。
同时,如果执行如上操作的语句可以通过模版被引用(比如HTML模板上绑定事件回调函数),则该语句会被$$invalidate
包裹。
$$invalidate
方法会执行如下操作:
- 更新
ctx
中保存状态的值; - 标记
dirty
,即标记App UI
中所有和 更新相关的部分将会发生变化; - 调度更新,在
microtask
中调度本次更新,所有在同一个macrotask
中执行的$$invalidate
都会在该macrotask
执行完成后被统一执行,最终会执行组件fragment
中的p
方法。p
方法会执行执行$$invalidate
中标记为dirty
对应的项更新对应DOM Element
。
Svelte 借由模版语法的约束,经过编译优化,可以直接建立状态与要改变的DOM节点的对应关系,使得 Svelte
执行细粒度的更新时对比使用虚拟DOM
的框架更有性能优势。