Vue.js设计与实现阅读-2
Vue.js设计与实现阅读-2
- 1、前言
- 2、框架设计的核心要素
- 2、1 提升用户体验
- 2、2 控制代码体积
- 2、3 Tree-Shaking
- 2、4 特性开关
- 2、5 错误处理
1、前言
上一篇我们了解到了
- 命令式和声明式的区别,前者关注过程,后者关注结果
- 了解了虚拟dom存在的意义,使找出差异这个过程消耗的性能最小化
- 学习了进行时、编译时、编译时+进行时的特点,初步知道了vue3是采用编译时+进行时的框架
2、框架设计的核心要素
2、1 提升用户体验
好的用户开发体验,是衡量框架是否优秀的指标之一。
提供友好的警告信息
当我们创建一个Vue.js应用,并把他挂载在一个不存在的dom节点,就会发现控制台有 warning 信息。
从警告信息中,能够快速知道失败原因,我们提供的选择器没有找到对应的 DOM 元素。如果Vue 内部不做处理,可能得到的是 Uncaught TypeError: Cannot read property ‘xxx’ of null 就不能很快定位到问题。
那 Vue 中是如何实现的,可以看 Vue 源码中有 warn 函数的调用
看代码可以看到,在创建Vue应用的时候,app.mount中调用了一个 normalizeContainer 函数,对于传入的参数进行处理,确保是一个有效的 DOM 元素。
在 normalizeContainer 函数中,可以看到图中圈出的 if 判断,当 处于开发者模式并且 通过 document.querySelector 方法没有找到匹配的 DOM 元素时,会输出警告信息。
再往里面看 warn 函数,发现最终都是调用了 console.warn 函数,进行输出警告
2、2 控制代码体积
框架的大小也是衡量框架的标准。同样情况下,使用的代码越少,体积就越小,浏览器加载资源的时间越少。
但是 Vue 中有大量的提示信息,越完善的提示信息就意味着越多的代码。
那 Vue3 中是如何处理的
看代码 会发现 每一个调用 warn 函数的地方 都会配合 __DEV __ 的常量检查
只有当 __DEV __ 为 true 的 前提下,才有可能会打印警告信息。这里的 DEV 常量就是达到目的的关键。
Vue.js 在输出资源的时候,会输出两个版本,开发环境和生产环境。当 Vue.js 构建用于开发环境的时候,会把 __DEV __ 设置为 true ,当处于生产环境的时候会设置为 false。那么那段警告代码就永远不会执行。
就能实现在开发环境为用户提供友好的警告信息,在生产环境中却不会增加代码体积。
2、3 Tree-Shaking
上面说到通过设置预定义常量 __DEV __ ,能够在生产环境中不包含用于打印警告信息的代码。但是这还不够,比如Vue内有很多组件,比如< transition > 组件,我们可能项目中都没用到这个组件,那他应该不需要包含在我们项目最终的构建资源中。Vue是如何实现的呢?
先揭晓答案吧,是通过 Tree-Shaking 实现的。 Tree-Shaking 用来消除那些永远不会被执行的代码(排除 dead code)。rollup.js和webpack 都支持 Tree-Shaking 。来看下 webpack 中, Tree-Shaking 如何工作。参考文档Tree-Shaking
创建一个 webpack 项目, 目录结构如下:
配置 webpack.config.js 如下
const path = require('path');module.exports = {entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, 'dist'),},mode: 'development',optimization: {usedExports: true,},
};
其中在 math 中导出了两个方法:
export function square(x) {return x * x;
}export function cube(x) {return x * x * x;
}
index.js 中调用 了 cube 方法
import { cube } from './math.js';function component() {const element = document.createElement('pre');element.innerHTML = ['你好 webpack!','5 的立方等于 ' + cube(5)].join('\n\n');return element;
}document.body.appendChild(component());
注意这里我们并没有导出 square 函数,按理说,最终的编译打包产物中应该是没有 square 函数的相关内容的。我们继续往下查看结果
使用 npm run build 查看 bundle.js中打包编译后的结果。
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ cube: () => (/* binding */ cube)\n/* harmony export */ });\n/* unused harmony export square */\nfunction square(x) {\n return x * x;\n }\n \n function cube(x) {\n return x * x * x;\n }\n\n//# sourceURL=webpack://webpack-demo/./src/math.js?");/***/ })/******/ });
看上方的 unused harmony export square 注释。仔细观察下面的代码会发现尽管没有引用 square,但它仍然被包含在 bundle 中。
在纯 ES 模块中,很容易识别出哪些文件有副作用,但是我们的项目没有办法达到这种纯度,因此我们需要提示 webpack 编译器哪些代码是纯粹的。
我们可以通过 /#PURE/ 注释来帮助 webpack,告诉他某个函数调用无副作用,她会被标记为 dead code,不会被执行且会被清除掉。
我们尝试在 square 函数前面加上这样一个标记,然后再来看 bundle.js 中的输出,可以看到已经没有 square函数的引入了。
(()=>{"use strict";document.body.appendChild(function(){const n=document.createElement("pre");return n.innerHTML=["你好 webpack!","5 的立方等于 "+(5,125)].join("\n\n"),n}())})();
基于以上 我们可以看到,在编写框架的时候可以合理的使用 /#PURE/ 注释。查看 Vue3 的源码,可以发现大量的 /#PURE/ 使用。
2、4 特性开关
设计框架的时候,会给用户提供多种功能,例如提供 A、B、C三个特性给用户,同时提供了a、b、c三个对应的开关,用户可以通过设置 a、b、c 为true 或者 false,代表开启或者关闭特性。
对于设置关闭的特性,可以利用 Tree-Shaking 机制让其不包含在最终资源中,带来了极大灵活性。
如何实现特性开关。其实类似于上面的 DEV 常量一样,本质上是利用 rollup.js 来预定义常量插件来实现。
比如 VUE_OPTIONS_API
__FEATURE_OPTIONS_API__: isBundlerESMBuild? `__VUE_OPTIONS_API__`: `true`,
其中 VUE_OPTIONS_API 是一个特性开关,用户可以通过设置 VUE_OPTIONS_API 预定义常量的值来控制是否要包含这段代码,这个标志是用来对 Vue2 做适配.
比如 Vue2中的 template、data 等选项其实都属于 Options API,但在 Vue3 中,这种 Options API 写得相对来说就比较少了,
现在一般在 Vue3 中编写 Composition API,默认情况下,这个 VUE_OPTIONS_API 标志默认值是 true,这就意味着默认情况下 Vue3 项目中会包含支持 Options API 的这部分代码。
那么,如果在项目中编写的都是 Composition API 代码,其实就不再需要这部分解析 Options API 的代码了,那么可以通过 设置 VUE_OPTIONS_API 为true,来剔除掉一些无用大代码,减少代码体积。
2、5 错误处理
错误处理是框架开发的重要环节。
假设我们提供了一个方法,
export default {foo(fn) {fn && fn()}
}
用户侧使用
import utils from 'utils.js'
utils.foo(() => {...
})
如果函数执行出错,有两个方法,1用户自己执行 try…catch处理
import utils from 'utils.js'
utils.foo(() => {try {//...} catch(e) {//...}
})
这样的话,用户每使用一个函数,都需要加一个错误处理程序。很烦。
第二个就是我们内部统一处理,封装一个错误处理函数, callWithErrorHandling。
export default {foo(fn) {callWithErrorHandling(fn)},bar(fn) {callWithErrorHandling(fn)}
}
function callWithErrorHandling(fn) {try {fn && fn()} catch(e) {console.log(e)}
}
这样代码看起来简洁,再升级下可以为用户提供统一的错误处理接口。
let handleError = null
export default {foo(fn) {callWithErrorHandling(fn)},// 暴露给用户,用户可以调用该函数注册统一的处理函数registerErrorHandler(fn) {handleError = fn}
}
function callWithErrorHandling(fn) {try {fn && fn()} catch(e) {// 将错误传递给用户的错误处理程序handleError(e)}
}
用户侧
import utils from 'utils.js' // 注册错误处理程序
utils.registerErrorHandler((e) => {// 做统一的处理,可以选择忽略,可以上报。console.log(e)})utils.foo(() => {/*...*/})utils.bar(() => {/*...*/})
相关文章:
Vue.js设计与实现阅读-2
Vue.js设计与实现阅读-2 1、前言2、框架设计的核心要素2、1 提升用户体验2、2 控制代码体积2、3 Tree-Shaking2、4 特性开关2、5 错误处理 1、前言 上一篇我们了解到了 命令式和声明式的区别,前者关注过程,后者关注结果了解了虚拟dom存在的意义&#x…...
GEM5 McPAT教程:源代码解读McPAT NoC功耗 arbiter部分
简介 McPAT用的很多,大多只是写个python或perl脚本替换xml文件.没有深入到为什么xml脚本这些值要换,以及这写填进去xml的值是怎么影响计算的.本问从源代码一步步读下来,解释每一步是如何计算的. power 构成: 动态功耗其实更相关于energy McPAT的power 核心是两类,动态和静态…...
使用组合框QComboBox模拟购物车
1.组合框: QComboBox 组合框:QComboBox 用于存放一些列表项 实例化 //实例化QComboBox* comboBox new QComboBox(this);1.1 代码实现 1.1.1 组合框的基本函数 QComboBox dialog.cpp #include "dialog.h" #include "ui_dialog.h"Dialog::Dialog…...
云服务器十大服务商——云服务器哪家好用
云服务器哪家便宜?2024最新整理你要的都在这!头部云厂商阿里云、腾讯云、华为云、京东云、UCloud等都在降价,阿腾云atengyun.com分享2024年云服务器租用价格给你惊喜! 便宜云服务器阿里云腾讯云华为云 2024年便宜云服务器汇总&…...
SQL DML
# DML—添加数据 1.给指定字段添加数据 INSERT INTO表名(字段名1,字段名2,...)VALUES(值1,值2...); 2.给全部字段添加数据 INSERT INTO表名VALUES(值1,值2,...); 3.批量添加数据 INSERT INTO表名(字段名1,字段名2,...)VALUES(值1,值2..…...
MySQL--基础篇
这里写目录标题 总览MySQl各个阶段基础篇总览 MySQL概述数据库相关概念查看本机MySQL版本号启停mysql打开windows服务管理windows命令行启停 连接mysql客户端mysql运行逻辑数据模型关系型数据库 总结 SQL总览SQL通用语法SQL语句分类DDL数据库操作表操作查询表创建表结构数据类型…...
[VUE]5-TypeScript
目录 1 TypeScript 介绍2、安装3、快速上手4、TypeScript 常用类型4.1 类型标注的位置4.2 字符串、数字、布尔类型4.3 字面量类型4.4 ⭐interface 类型4.5 class 类型 🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,…...
Linux指令(一)
今天来学习Linux的一些基本的指令。 今天要学习的指令有ls,pwd,mkdir,cd,touch,rm等。 指令的格式 在Linux中,指令的语法通常遵循以下格式: command [options] [arguments] command 是要执行…...
C语言中的回文素数
任意的整数,当从左向右读与从右向左读是相同的,且为素数时,称为回文素数。求 1000 以内的所有回文素数。 算法思想 实例的重点是判断一个数是否是回文素数。要输出 1000 以内的所有回文素数,首先应判断这个数是否是素数…...
前端生成pdf之html2canvas+jsPDF,以及解决图片不显示bug
前端如何生成pdf 开发背景: 需要给页面中相应的内容生成pdf,查找文档后发现要用到两个插件。html2canvas 以及 jsPDF html2canvas 给dom结构转化为canvas,然后生成各种类型图片jsPDF 把canvas 生成的图片url 转化为pdf // 插入图片 pdf.addI…...
PHP常用符号和函数
// 单行注解 /* */ 多行注解 引号的使用 ’ ’ 单引号,没有任何意义,不经任何处理直接拿过来; ” “双引号,php动态处理然后输出,一般用于变量. 变量形态: 一种是True 即 真的; 另一种是False 即假的 常见变量形态: string 字串(数字\汉字\等等) integer 整数(1、2、…...
C#,入门教程(12)——数组及数组使用的基础知识
上一篇: C#,入门教程(11)——枚举(Enum)的基础知识和高级应用https://blog.csdn.net/beijinghorn/article/details/123917587 数组是一种数据集合,是一组完全相同的、按顺序存放的数据。 需要记住数组的几个特征&…...
C语言中的副作用、序列点以及复杂表达式的求值顺序
C语言中复杂表达式的求值顺序 num (5 2) * (9 * 6);如果我问你:上面的c程序在执行的时候到底是先算(5 2)还是(9 * 6)?你会怎么回答? 无非就两种:先算(5 2ÿ…...
C++学习笔记——队列模拟
目录 一、模拟队列 二、模拟队列的知识点 三、队列 3.1入队操作 3.2出队操作 3.3访问队首元素 3.4访问队尾元素 3.5判断队列是否为空 3.6获取队列的大小 四、实现队列的基本功能 一、模拟队列 当涉及到数据存储和处理时,队列是一种常见的数据结构&#x…...
jvm垃圾回收相关的算法
什么是垃圾 JVM主要通过以下几种方式来判断对象是否需要回收: 引用计数法:JVM通过引用计数器来判断对象的引用数量,当引用数量为0时,表示对象可以被回收。 可达性分析算法:JVM通过根对象(如栈中的引用、静…...
每日coding
2085、统计出现过一次的公共字符串 给你两个字符串数组 words1 和 words2 ,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。 示例 1: 输入:words1 ["leetcode","is","amazing","as"…...
软件工程_复习
软件工程 软件危机(1968 60年代) 产生软件危机的原因: 一方面与软件本身的特点有关,另一方面也和软件开发和维护的方法不正确有关。 与软件本身特点有关: 1.软件不同于硬件,软件是计算机系统中的逻辑部件,缺乏“可见性”,管理和控制软件开发过程相当困难 2.软件在运行过…...
07GoF之三种工厂模式
GoF(Gang of Four):四人组,《Design Patterns: Elements of Reusable Object-Oriented Software》(《设计模式》)的作者,设计了23种设计模式.但时代发展,还有其它的设计模式,比如:JavaEE的设计模式(DAO模式…...
JAVA面试部分——后端-线程前篇
3.1 线程和进程 在计算机科学中,进程和线程是操作系统管理资源的两种不同方式。 进程(Process):是程序在计算机上的一次执行活动。每个进程都有自己的内存空间,包括代码、数据和系统资源。一个进程可以包含多个线程。…...
【小沐学C++】C++ 实现鼠标键盘钩子HOOK
文章目录 1、简介2、相关函数2.1 SetWindowsHookEx2.2 UnhookWindowsHookEx2.3 CallNextHookEx 3、相关结构体3.1 KBDLLHOOKSTRUCT3.2 MSLLHOOKSTRUCT 4、挂钩过程5、代码测试5.1 代码1 结语 1、简介 https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-hooks 挂…...
【pycharm】常见问题与解决
记录一些Pycharm中经常遇到的问题 1. “Open file or Project” always in loading state (hang) a) 老版本 (2021年左右) since build 211.6693.14, it is possible to use a native file chooser on Windows. The feature is experimental; to enable it, add the followi…...
flask web学习之表单(一)
文章目录 一、使用Flask-WTF处理表单1.1 安装Flask-WTF库1.2 定义WTForms表单类常用的WTForm字段实例化字段类常用参数常用的WTForm验证器 1.3 输出HTML代码使用render_kw属性在调用字段时传入 1.4 在模板中渲染表单 在web程序中,表单是用户交互最常见的方式之一。用…...
@ControllerAdvice 使用场景
ControllerAdvice 是Spring 框架中的注解,多用在Spring MVC应用程序中。 使用场景1:处理异常 # 示例1 import org.apache.ibatis.javassist.NotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.Respons…...
二极管选型怎么选?常用参数要熟练~
同学们大家好,今天我们继续学习杨欣的《电子设计从零开始》,这本书从基本原理出发,知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例,可以说是全面系统地介绍了电子设计所需的知识…...
【小白专用】C#关于角色权限系统
(C#)用户、角色、权限 https://www.cnblogs.com/huangwen/articles/638050.html 权限管理系统——数据库的设计(一) https://www.cnblogs.com/cmsdn/p/3371576.html 权限管理系统——菜单模块的实现(二) …...
代码随想录算法训练营
一刷打卡记录: 日期打卡2023/10/25 day01二分查找有点转不过弯,快慢指针能理解,自己写也可能写不出来,但是能记住了,能看懂,还有其他解法待补充看完,花了挺长时间的2023/10/26 day02还好&#…...
统计学-R语言-3
文章目录 前言给直方图增加正态曲线的不恰当之处直方图与条形图的区别核密度图时间序列图洛伦茨曲线计算绘制洛伦茨曲线所需的各百分比数值绘制洛伦茨曲线 练习 前言 本篇文章是介绍对数据的部分图形可视化的图型展现。 给直方图增加正态曲线的不恰当之处 需要注意的是&#…...
spring动态控制定时任务
在spring框架中,对于简单的定时任务,可以使用 Scheduled 注解实现,在实际项目中,经常需要动态的控制定时任务,比如通过接口增加、启动、停止、删除定时任务,动态的改变定时任务的执行时间等。 我们可以通过…...
3. Mybatis 中SQL 执行原理
2. Mybatis 中SQL 执行原理 这里有两种方式,一种为常用的 Spring 依赖注入 Mapper 的方式。另一种为直接使用 SqlSessionTemplate 执行 Sql 的方式。 Spring 依赖注入 Mapper 的方式 Mapper 接口注入 SpringIOC 容器 Spring 容器在扫描 BeanDefinition 阶段会扫…...
第一次在RUST官方论坛上留言发布我的Rust板箱
第一次在RUST官方论坛上发帖子,有点紧张~地址在这里: 【My Rust Crate】obtains linux local information - The Rust Programming Language Forum (rust-lang.org)...
div+css免费网站模板下载/软文优化
1 什么是板卡文件?首先先介绍一下什么是板卡文件,在安装完Vivado开发工具之后,在安装目录下会有一个board_files的文件夹。例如,Vivado安装在C盘,则board_files文件夹路径为:C:\Xilinx\Vivado\2018.1\data\…...
海淀高端网站建设/河南网站定制
1、打开毕业论文,找到一个表格这里我随便写了一个表格,进行练习使用,数据本身没有参考价值2、点击一下表格,点击表设计,点击下面那个箭头3、选择新建表格样式4、首先,我们给这个模板命名为三线表࿰…...
5118网站的功能/最新热点新闻
手动创建一个用户角色对象进行返回时可以用到 会自动根据","分割成权限数组; 视频连接 登录过滤器链 关于请求重定向外网 实现接口重写方法,并在配置中使用这个控制器; 使用: 同理也可以定义一个失败的࿰…...
wordpress 拼音别名/信息流广告公司一级代理
前言idea作为一个java开发的便利IDE工具,个人是比较喜欢的,今天来探索个小功能: 导出单个类文件为jar包!JAR文件的全称是Java Archive File,意思就是Java档案文件。通常JAR文件是一种压缩文件,与常见的ZIP压…...
免费追剧网站/官网首页入口百度
程序员往往渴望加入的是一支“30%的时间在写代码,而70%的时间在喝着咖啡讨论着如何将产品做好”的团队。可现实情况却是,团队在一边超负荷的做着需求,一边改着没完没了的Bug,软件工作已经无可挽回的沦落成了体力劳动,别…...
赣州市做网站设计/萌新seo
下表包含了Oracle不同产品的缺省端口,例如Oracle Database,Oracle Application Server的默认端口。更改这些默认端口可以防止简单的数据库攻击,除了端口扫描。在Oracle中经常会发生不能改变默认端口的情况,因为Oracle的端口是硬编…...