缪老师 发表于 2023-12-29 04:01:06

svelte响应式原理

svelte文件编译为js后的结构

源代码:



    <p>fullName is {firstName} {lastName}</p>
    <p>age is {age}</p>
   
      <button on:click={handleChangeName}>change name</button>
      <button on:click={handleChangeAge}>change age</button>
   
编译后的js代码结构
function create_fragment(ctx) {
        const block = {
                c: function create() {
                        // ...
                },
                m: function mount(target, anchor) {
                        // ...
                },
                p: function update(ctx, ) {
                        // ...
                },
                d: function destroy(detaching) {
                        // ...
                }
        };
        return block;
}

function instance($$self, $$props, $$invalidate) {
        let firstName = '张';
        let lastName = '三';
        let age = 18;

        function handleChangeName() {
                $$invalidate(0, firstName = '王');
                $$invalidate(1, lastName = '二');
        }

        function handleChangeAge() {
                $$invalidate(2, age = 28);
        }


        return ;
}

class Name extends SvelteComponentDev {
        constructor(options) {
                init(this, options, instance, create_fragment, safe_not_equal, {});
        }
}初始化调用init方法

function init(component, options, instance, create_fragment, ...,dirty = [-1]) {
        // $$属性为组件的实例
        const $$ = component.$$ = {
              ...
          // dirty的作用是标记哪些变量需要更新,
          // 在update生命周期的时候将那些标记的变量和对应的dom找出来,更新成最新的值。
          dirty,
          // fragment字段为一个对象,对象里面有create、mount、update等方法
          fragment: null,
          // 实例的ctx属性是个数组,存的是组件内的顶层变量、方法等。按照定义的顺序存储
          ctx: [],
          ...
      }

      // ctx属性的值为instance方法的返回值。
      // instance方法就是svelte文件编译script标签代码生成的。
      // instance方法的第三个参数为名字叫$$invalidate的箭头函数,
      // 在js中修改变量的时候就会自动调用这个方法
      $$.ctx = instance
                ? instance(component, options.props || {}, (i, ret, ...rest) => {
                        const value = rest.length ? rest : ret;
                        if ($$.ctx && not_equal($$.ctx, $$.ctx = value)) {
                                make_dirty(component, i);
                        }
                        return ret;
                })
                : [];

      // 调用create_fragment方法
      // 并且在后续对应的生命周期里面调用create_fragment方法返回的create、mount、update等方法
      $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
}点击change name按钮,修改firstName和lastName的值

let firstName = '张'
let lastName = '三'
let age = 18

function handleChangeName() {
        // firstName变量第一个定义,所以这里是0,并且将新的firstName的值传入$$invalidate方法
        $$invalidate(0, firstName = '王');
      // lastName变量第二个定义,所以这里是1,并且将新的firstName的值传入$$invalidate方法
        $$invalidate(1, lastName = '二');
}

// ...再来看看invalidate函数的定义,invalidate函数就是在init时调用instance的时候传入的第三个参数
(i, ret, ...rest) => {
        // 拿到更新后的值
        const value = rest.length ? rest : ret;
      // 判断更新前和更新后的值是否相等,不等就调用make_dirty方法
        if ($$.ctx && not_equal($$.ctx, $$.ctx = value)) {
              // 第一个参数为组件对象,第二个参数为变量的index。
          // 当更新的是firstName变量,firstName是第一个定义的,所以这里的i等于0
          // 当更新的是lastName变量,lastName是第二个定义的,所以这里的i等于1
                make_dirty(component, i);
        }
        return ret;
}make_dirty方法的定义
function make_dirty(component, i) {
        // dirty初始化的时候是由-1组成的数组,dirty === -1说明是第一次调用make_dirty方法。
        if (component.$$.dirty === -1) {
                dirty_components.push(component);
          // 在下一个微任务中调用create_fragment方法生成对象中的update方法。
                schedule_update();
          // 将dirty数组的值全部fill为0
                component.$$.dirty.fill(0);
        }
        component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
}
再来看看component.$$.dirty[(i / 31) | 0] |= (1
页: [1]
查看完整版本: svelte响应式原理