🚀Svelte原理和进阶看这篇就够了🚀2

简介: 🚀Svelte原理和进阶看这篇就够了🚀

Svelte运行时原理

现在我们又有了一个新的问题。我们已经可以感知到值的变化,那是怎么将值得变化更新到页面中的了。

你可能马上想到的是create_fragment返回的updata方法啊。这里仅仅是提供了更新页面DOM的方法,那是什么样的时机调用这个更新方法的呢?

init方法

其实,svelte的编译结果是运行时运行的代码。在进入运行时,首先执行init方法,该方法大致流程如下:

  • 💎初始化状态
  • 💎初始化周期函数
  • 💎执行instance方法,在回调函数中标记脏组件
  • 💎执行所有beforeUpdate生命周期的函数
  • 💎执行创建片段create_fragment函数
  • 💎挂载当前组件并执行create_fragement返回的m(mounted)方法
  • 💎执行flush方法

你可以跳过这段代码,不影响阅读

export function init(
  component,
  options,
  instance,
  create_fragment,
  not_equal,
  props,
  append_styles,
  dirty = [-1]
) {
  const parent_component = current_component;
  set_current_component(component);
  const $$: T$$ = component.$$ = {
    fragment: null,
    ctx: [],
    // state
    props,
    update: noop,
    not_equal,
    bound: blank_object(),
    // lifecycle
    on_mount: [],
    on_destroy: [],
    on_disconnect: [],
    before_update: [],
    after_update: [],
    context: new Map(options.context || (parent_component ? parent_component.$$.context : [])),
    // everything else
    callbacks: blank_object(),
    dirty,
    skip_bound: false,
    root: options.target || parent_component.$$.root
  };
  append_styles && append_styles($$.root);
  let ready = false;
  $$.ctx = instance
    ? instance(component, options.props || {}, (i, ret, ...rest) => {
        const value = rest.length ? rest[0] : ret;
        if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
            if (!$$.skip_bound && $$.bound[i]) $$.bound[i](value);
            if (ready) make_dirty(component, i);
        }
        return ret;
    })
    : [];
  $$.update();
  ready = true;
  run_all($$.before_update);
  // `false` as a special case of no DOM component
  $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
  if (options.target) {
    if (options.hydrate) {
        start_hydrating();
        const nodes = children(options.target);
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        $$.fragment && $$.fragment!.l(nodes);
        nodes.forEach(detach);
    } else {
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        $$.fragment && $$.fragment!.c();
    }
    if (options.intro) transition_in(component.$$.fragment);
    mount_component(component, options.target, options.anchor, options.customElement);
    end_hydrating();
    flush();
  }
  set_current_component(parent_component);
}

看起来,flush方法很可能才是我们需要的答案。

flush方法

flush的方法主要做了一件事:

遍历需要更新的组件(dirty_components),然后更新它,并且调用afterUpdate方法。

export function flush() {
  // Do not reenter flush while dirty components are updated, as this can
  // result in an infinite loop. Instead, let the inner flush handle it.
  // Reentrancy is ok afterwards for bindings etc.
  if (flushidx !== 0) {
    return;
  }
  const saved_component = current_component;
  do {
    // first, call beforeUpdate functions
    // and update components
    try {
        while (flushidx < dirty_components.length) {
            const component = dirty_components[flushidx];
            flushidx++;
            set_current_component(component);
            update(component.$$);
        }
    } catch (e) {
        // reset dirty state to not end up in a deadlocked state and then rethrow
        dirty_components.length = 0;
        flushidx = 0;
        throw e;
    }
    set_current_component(null);
    dirty_components.length = 0;
    flushidx = 0;
    // then, once components are updated, call
    // afterUpdate functions. This may cause
    // subsequent updates...
    for (let i = 0; i < render_callbacks.length; i += 1) {
        const callback = render_callbacks[i];
        if (!seen_callbacks.has(callback)) {
            // ...so guard against infinite loops
            seen_callbacks.add(callback);
            callback();
        }
    }
    render_callbacks.length = 0;
  } while (dirty_components.length);
  while (flush_callbacks.length) {
    flush_callbacks.pop()();
  }
  update_scheduled = false;
  seen_callbacks.clear();
  set_current_component(saved_component);
}

我们再来看看具体的更新操作update函数做了啥

  • 首先执行所有的before_update方法
  • 然后执行create_fragment返回的p(update)方法
function update($$) {
    if ($$.fragment !== null) {
        $$.update();
        run_all($$.before_update);
        const dirty = $$.dirty;
        $$.dirty = [-1];
        $$.fragment && $$.fragment.p($$.ctx, dirty);
        $$.after_update.forEach(add_render_callback);
    }
}

好了,我们总结下:在运行时

  • 💎首先,初始化状态、初始化周期函数
  • 💎接着,执行instance方法,在回调函数中标记脏组件
  • 💎接着,执行所有beforeUpdate生命周期的函数
  • 💎然后,执行创建片段create_fragment函数
  • 💎接着,挂载当前组件并执行create_fragement返回的m(mounted)方法
  • 💎然后,执行flush方法
  • 💎首先,执行所有的before_update方法
  • 💎然后,执行create_fragment返回的p(update)方法
  • 💎最后,执行afterUpdate方法

总结

好了,今天的分享就这些了,总的来说,Svelte的响应式原理虽然很朴素,但是却拥有了更好的性能,同时也降低了开发者的记忆负担。我觉得这是svelte最成功的地方。

如果你发现文章有错误的地方,请及时告诉我,十分感谢。

今天的分享就到这了,如果你觉得还不错,也可以关注我的微信公众号:萌萌哒草头将军

相关文章
|
3月前
|
存储 Python
Python编程入门:从零开始的代码之旅
【9月更文挑战第4天】本文将带领初学者步入Python的世界,通过简明的语言和直观的例子,逐步揭示编程的乐趣。我们将一起构建基础的数据结构,探索控制语句的奥秘,并实现简单的函数。无论你是编程新手还是希望巩固基础,这篇文章都是你理想的起点。让我们开始吧,一步步将代码块搭建成思维的宫殿!
39 2
|
7月前
|
搜索推荐 开发者
【Uniapp 专栏】探究 Uniapp 组件化开发的奥秘
【5月更文挑战第12天】Uniapp的组件化开发模式正引领移动应用开发潮流,提升开发效率并简化维护。通过将应用拆分为独立、可复用的组件,开发者能快速构建和优化功能,降低出错风险。基础组件满足基本需求,自定义组件则针对特定业务场景。Uniapp提供简洁的组件定义、通信支持及组件库管理,促进数据共享和功能协同。然而,组件设计需考虑通用性、扩展性和依赖管理。组件化开发在Uniapp中日益重要,为开发者创造更多价值,激发创新潜力。
91 4
【Uniapp 专栏】探究 Uniapp 组件化开发的奥秘
|
7月前
|
存储 移动开发 前端开发
【Uniapp 专栏】Uniapp 架构设计与原理探究
【5月更文挑战第12天】Uniapp是一款用于跨平台移动应用开发的框架,以其高效性和灵活性脱颖而出。它基于HTML、CSS和Vue.js构建视图层,JavaScript处理逻辑层,管理数据层,实现统一编码并支持原生插件扩展。通过抽象平台特性,开发者能专注于业务逻辑,提高开发效率。尽管存在兼容性和复杂性挑战,但深入理解其架构设计与原理将助力开发者创建高质量的跨平台应用。随着技术进步,Uniapp将继续在移动开发领域扮演重要角色。
244 1
【Uniapp 专栏】Uniapp 架构设计与原理探究
|
6月前
|
算法 开发工具 数据安全/隐私保护
练手必备!Python编程实战—23个有趣的实战项目带你快速进阶
Python的练手项目有哪些值得推荐? 已经有6.4W关注,700W次浏览,回答都有450条了,本来遇到这种问题我是不会回答的,毕竟已经有太多人给出了答案,我再去回答就没什么意义了。 但想了想确实有很多刚学Python的并不清楚从哪里去找项目来练手,于是就有了这篇文章,基于这个目的,我也是找了好久,最后还是选择了分享这份手册,毕竟里面有细致的讲解,确实更适合练手一些。
|
7月前
|
编译器 程序员 Linux
【C++入门(上篇)】C++入门学习
【C++入门(上篇)】C++入门学习
|
缓存 JavaScript 算法
🚀Svelte原理和进阶看这篇就够了🚀1
🚀Svelte原理和进阶看这篇就够了🚀
|
XML IDE 编译器
【C++】C++ 基础进阶【二】开发技巧
C++基础进阶,关于开发环境开发工具的一些便捷使用方式,提高生产力
171 0
【C++】C++ 基础进阶【二】开发技巧
|
前端开发 C# 数据库管理
(3) MasaFramework 入门第三篇,使用MasaFramework
(3) MasaFramework 入门第三篇,使用MasaFramework
111 0
(3) MasaFramework 入门第三篇,使用MasaFramework
|
前端开发 JavaScript 中间件
我学会了,react上手知识点(上篇)
本篇文章记录的是上手react并做好一个React项目的大概知识点,比如jsx本质、生命周期、组件嵌套、父子通信、组件通信、插槽机制、跨组件通信、setState、react性能优化、ref、受控和非受控组件、高阶组件、React中使用样式。
152 0
我学会了,react上手知识点(上篇)
|
前端开发 JavaScript API
渐进式手敲Vue3.0框架 - 2万字以上 - 持续更新
为了更好的理解Vue3源码我计划使用渐进式的方法完成一个简写版的Vue框架。
174 0

热门文章

最新文章