框架设计浅析

209 阅读4分钟

vue框架的设计思想--渐进、轻量、数据驱动、组件化、自底向上

框架设计基本原则

编程范式

从范式上来讲,视图层框架通常分为命令式和声明式

  • 设计原则:在保证可维护性的同时让性能损失最小化
  • 命令式编程
    • 关注过程是一种编程范式,描述了完成一个功能的详细逻辑与步骤;
    • 如早期的jQuery就是命令式编程
  • 声明式编程
    • 不关注过程(只是将过程进行隐藏了而已),只关注结果的范式
    • 如Vue中的常见语法(如模板双花括号);
    • Vue内部实现一定是命令式的,而暴露给用户的是声明式的
  • 声明式编程的性能不优于命令式编程
    • 命令式编程可以做到极致的性能优化,明确知道哪些发生了变更,只做必要变更即可
    • 而声明式编程需要找到前后差异,然后再更新有变化的地方,性能消耗上比命令式编程多了找出差异的性能消耗
    • 当声明式编程可以最小化找出差异的性能消耗时,其性能就无限接近命令式编程了 - Vue虚拟DOM就是为此设计的
  • 声明式编程可以简单理解为封装了命令式编程的代码
  • 声明式编程代码可维护性比命令式更强

框架的不同输出产物

  • 可以让用户通过<script>标签直接引用并使用,需要输出IIFE格式的资源;
  • 为了让用户通过<script type="module">引用并使用,需要输出ESM格式的资源;
    • ESM格式资源类型一:用于浏览器的esm-browser.js
      • 直接将__DEV__常量替换为字面量true或false
    • ESM格式资源类型一:用于打包工具的esm-bundler.js
      • 直接将__DEV__常量替换为process.env.NODE_ENV !== 'production'语句

支持Tree-Shaking

Tree-Shaking是指消除那些永远都不会被执行的代码,永远都不会执行的代码被称为dead code,这些代码不会出现在最终产物中,在构建资源的时候就会被移除;
如Vue中的相关打印信息,通过配置__dev__参数来实现生产环境和开发环境的区别,在生产环境时会将其设置为false,标识该代码模块不会执行,然后在打包的时候就不会将其编译进最终包的

  • 警告信息一般也利用Tree-Shaking机制配合构建工具预定义常量的能力,来实现开发环境打印警告信息生产环境下生产环境下不包含这些逻辑,进而实现线上代码的可控性;
  • 错误处理可以保证框架的健壮性,可以通过向用户提供可配置的错误处理来达到用户可控性
// utils.js
let handleError = null;
export default {
  foo(fn) {
    callWithErrorHandling(fn);
  },
  // 用户可以调用该函数注册统一的错误处理函数
  registerErrorHandler(fn) {
    handleError = fn;
  },
};
function callWithErrorHandling(fn) {
  try {
    fn && fn();
  } catch (e) {
    // 将捕获到的错误传递给用户的错误处理程序
    handleError(e);
  }
}
副作用 - 不会标记为dead code

副作用是指调用函数时会对外部产生影响,如修改了某个值,但是简单的读取也有可能产生副作用,例如会触发代理对象的get拦截,因此需要单独对这些逻辑进行处理,以rollup.js为例

  • /*#__PURE__*/
    • 该注释代码会告诉打包工具,其后的这个函数逻辑不会产生副作用,可以放心进行Tree-Shaking
    • /*#__PURE__*/ foo(),表示Foo函数的执行不会产生副作用

前端架构设计原则

image.png

拓展

innerHTML和虚拟DOM浅析

  • 创建页面时的性能对比
    • innerHTML创建页面性能:HTML字符串拼接计算量 + innerHTML的DOM计算量,即渲染HTML字符串(JS运算)+新建所有DOM元素(DOM运算)
    • 虚拟DOM创建页面性能:创建JS对象计算量+创建真实DOM计算量创建VNode(JS运算)+新建所有DOM元素(DOM运算)
    • 结论:没有太大区别,细究的话虚拟DOM性能可能更差
  • 更新页面时性能对比
    • innerHTML更新页面性能:重新创建HTML字符串、重新设置DOM元素的innerHTML属性(重新设置innerHTML等价于销毁所有旧的DOM元素,再重新创建新的DOM元素)
      • 渲染HTML字符串+销毁所有旧的DOM+新创建所有新的DOM
    • 虚拟DOM更新页面性能:重新创建JS对象(即虚拟DOM树),然后比较新旧虚拟DOM树,找到变化后更新它
      • 创建新的JS对象+Diff对比+必要的DOM更新
    • 影响性能的其他因素 - 页面大小与复杂度
      • 虚拟DOM基本影响不大(与数据量变化相关),innerHTML性能与复杂度成正比(与模板大小相关)
    • 结论
      • JS层面的计算:虚拟DOM比innerHTML多出一个