javascript - SvelteJS与ReactJS渲染差异(重绘/重排)

标签 javascript reactjs svelte virtual-dom svelte-3

这是我对DOM和浏览器如何工作的幼稚理解

每当DOM中的某些内容(真实dom)更改时,浏览器就会重新绘制或重排该DOM。因此,用更简单的术语来说,每次DOM更改时,浏览器都需要重新计算CSS,进行布局并重新绘制网页。这是在真正的dom中花费时间的原因。

因此,React附带了这个虚拟DOM,它的实际作用是将更改批量进行批处理,然后调用一次将它们应用于实际域。因此,最大程度地减少了重焊和重绘(repaint)。

那斯维尔特呢。如果直接操作DOM,它将如何控制浏览器的重绘/重排。

最佳答案

除了上面的(正确)答案之外:Svelte还可以“编译”您提供给它的代码,因此最终代码可以在没有库运行时的情况下执行(与React相比)。而且它创建了可读性强的代码,因此绝对有可能了解其内部工作原理。

注意:这将是更长的答案-仍然遗漏了有关斯维尔特(Svelte)背后发生的事情的许多详细信息。但是,我希望这有助于揭开某些幕后神秘面纱。同样,这也是Svelte从v3.16.x起执行操作的方式。由于这是内部的,因此可能会更改。但是,我仍然发现了解实际情况总是很有意义的。

所以,我们开始。

最重要的是: Svelte教程具有一项有用的功能,可让您查看生成的代码(在“结果” Pane 旁边)。乍一看可能有点吓人,但很快您就可以掌握它了。

下面的代码将基于此示例(但经过进一步简化):Svelte tutorial - reactivity/assignments

我们的示例组件定义(即App.svelte)如下所示:

<script>
    let count = 0;

    function handleClick() {
        count += 1;
    }
</script>

<button on:click={handleClick}>{count}</button>

基于此组件定义,Svelte编译器创建一个函数,该函数将创建一个“片段”,该片段接收“上下文”并与之交互。
function create_fragment(ctx) {
    let button;
    let t;
    let dispose;

    return {
        c() {
            button = element("button");
            t = text(/*count*/ ctx[0]);
            dispose = listen(button, "click", /*handleClick*/ ctx[1]);
        },
        m(target, anchor) {
            insert(target, button, anchor);
            append(button, t);
        },
        p(ctx, [dirty]) {
            if (dirty & /*count*/ 1) set_data(t, /*count*/ ctx[0]);
        },
        i: noop,
        o: noop,
        d(detaching) {
            if (detaching) detach(button);
            dispose();
        }
    };
}

片段负责与DOM交互,并将随组件实例一起传递。简而言之,其中的代码
  • “c”将在上运行创建(在内存中创建DOM元素并设置事件处理程序)
  • “m”将在上运行(将元素附加到DOM)
  • “p”将在更新上运行,即当某些内容(包括 Prop )更改
  • “i” /“o”与前奏/外奏(即过渡)有关
  • “d”将在上运行destroy

  • 注意:像element或set_data这样的函数实际上非常容易实现。
    例如,function元素只是document.createElement的包装:
    function element(name) {
        return document.createElement(name);
    }
    

    上下文(ctx)将保存所有实例变量以及函数。它不过是一个简单的数组。由于Svelte在编译时“知道”每个索引的含义,因此它可以在其他地方硬引用这些索引。

    这段代码实质上定义了实例上下文:
    function instance($$self, $$props, $$invalidate) {
        let count = 0;
    
        function handleClick() {
            $$invalidate(0, count += 1);
        }
    
        return [count, handleClick];
    }
    

    实例方法以及create_fragment都将从另一个函数调用init调用。它涉及更多的内容,因此您可以查看此link to the source,而不是在此处复制和粘贴。

    $$ invalidate将确保将count变量设置为脏变量并安排更新。当下一次更新运行时,它将查看所​​有“脏”组件并进行更新。这是如何发生的实际上更多是实现细节。如果有兴趣,请在flush function中设置一个断点。

    实际上,如果您真的想更深入一点,我建议克隆template应用程序,然后创建一个简单的组件,对其进行编译,然后检查“bundle.js”。如果删除源映射或将其禁用,也可以调试实际代码。

    因此,例如,如下设置rollup.config.js:
        output: {
            sourcemap: false,
            format: 'iife',
            name: 'app',
            file: 'public/build/bundle.js'
        },
        plugins: [
            svelte({
                dev: false,
    

    注意:如上所示,建议将开发人员模式也设置为false,因为这将创建更简洁的代码。

    一项简洁的功能:运行我们的应用程序后,您还可以访问应用程序变量(由于它被绑定(bind)为立即调用的函数表达式,因此已分配给全局窗口对象)。

    因此,您可以打开控制台并简单地说
    console.dir(app)
    

    会产生这样的东西
    App
        $$:  
            fragment: {c: ƒ, m: ƒ, p: ƒ, i: ƒ, o: ƒ, …}
            ctx: (2) [0, ƒ]
            props: {count: 0}
            update: ƒ noop()
            not_equal: ƒ safe_not_equal(a, b)
            bound: {}
            on_mount: []
            on_destroy: []
            before_update: []
            after_update: []
            context: Map(0) {}
            callbacks: {}
            dirty: [-1]
            __proto__: Object
        $set: $$props => {…}
    

    一个很酷的功能是,您可以自己使用$ set方法来更新实例。例如这样:
    app.$set({count: 10})
    

    还有Svelte DevTools试图使Svelte的内部结构更加平易近人。当我亲自试用它们时,它们似乎会以某种方式影响我的应用程序的渲染性能,因此我不会自己使用它们。但是肯定值得一看。

    好吧,那里有。我知道这仍然是技术性的,但是我希望它有助于更​​好地了解Svelte编译代码的功能。

    关于javascript - SvelteJS与ReactJS渲染差异(重绘/重排),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58902385/

    相关文章:

    javascript - 如何使用 Jquery/Javascript 选择某个元素

    javascript - 轮播中的第一个元素在加载时没有应用 100% 的高度?

    javascript - props 值未在 vuejs 中渲染

    reactjs - 使用 TypeScript 在 React Native 上传递 refs : (property) React. MutableRefObject<null>.current : null Object is possibly 'null' . ts(2531)

    javascript - React V16.7 TypeError : Object(. ..) 不是一个函数

    navigation - SvelteKit 中的嵌套路由

    javascript - 如何在 ES6 类中使用匿名函数

    javascript - useRef 当前仅在第二次更新时获取其值

    css - Svelte/Sapper构建-似乎在构建后仍然存在旧CSS?

    javascript - Svelte.js 组件属性在带有 customElement : true 的脚本标记内未定义