第 1 章、权衡的艺术

命令式 or 声明式

命令式:关注过程

声明式:关注结果

声明式直接声明想要的结果,框架帮用户封装好命令式的代码,所以在封装的过程中要做一些其他的事情来(生成要做的事情/找出差异)生成命令式的代码,优势是可维护性强,但是性能:命令式 ≥ 声明式

框架设计要做的就是,保持可维护性,同时让性能损失更少。

虚拟 DOM

性能:innerHTML < 虚拟DOM < 原生JavaScript

心智负担/可维护性:虚拟DOM < innerHTML < 原生JavaScript

运行时和编译时

三种选择:纯运行时、运行时+编译时、纯编译时

手写vdom太麻烦,所以通过模板 or JSX 完成书写,但是这些还需要经历一次编译

Vue:运行时+编译时

Svelte: 纯编译时

第 2 章、设计框架要注意什么?

提升开发体验

用户未按要求使用时的错误提示,console 自定义 formatter 直观显示数据

控制框架代码的体积

开发环境提供良好提示,不增加生产环境体积。(通过 __DEV__ 变量判断)

Tree-Shaking

使用 ESM

如果一个函数有副作用,将不会被 Tree-Shaking 删除,通过 /*#__PURE__*/ 在打包工作( rollup/webpack )中声明没有副作用。

输出产物

IIFE:rollup format: 'iife'

ESM: format: 'esm'

CommonJS: format: 'cjs'

特性开关

用户关闭的特性,利用 Tree-Shaking 不打包到最终资源里。比如在 Vue3 中,对于 options API

处理错误

执行用户提供的函数时,做统一的错误处理(try...catch),并提供给用户错误接口来处理。(可以错误上报等。)

TypeScript类型支持

第 3 章、Vue3 的设计思路

声明式的描述 UI

模板描述,或者虚拟DOM描述

渲染器

渲染器:把虚拟DOM变成真实DOM并渲染到浏览器页面。一个简单的渲染器实现:

点击查看代码
const vnode = {
tag: 'div',
props: {
onClick: () => alert('hello'),
},
children: 'click me',
}; function renderer(vnode, container) {
const el = document.createElement(vnode.tag);
for (const key in vnode.props) {
if (/^on/.test(key)) {
// on 开头是事件
el.addEventListener(
key.substr(2).toLowerCase(), // 事件名 onClick -> click
vnode.props[key] // 事件处理函数
);
}
}
// 处理 children
if (typeof vnode.children === 'string') {
el.appendChild(document.createTextNode(vnode.children));
} else if (Array.isArray(vnode.children)) {
vnode.children.forEach((child) => {
renderer(child, el);
});
} container.appendChild(el);
} renderer(vnode, document.body);

组件的本质

组件就是一组 DOM 元素的封装。上面的渲染器兼容组件(包括函数写法和对象写法):

点击查看代码
const MyComponent = function() {
return {
tag: 'div',
props: {
onClick: () => alert('hello'),
},
children: 'click me - MyComponent',
}
} const MyComponent1 = {
render() {
return {
tag: 'div',
props: {
onClick: () => alert('hello'),
},
children: 'click me - MyComponent1',
}
}
} const vnode = {
tag: MyComponent
}; function renderer(vnode, container) {
if (typeof vnode.tag === 'string') {
// 标签元素
mountElement(vnode, container);
} else if (typeof vnode.tag === 'function') {
// 函数描述组件
mountFunctionComponent(vnode, container);
} else if (typeof vnode.tag === 'object') {
// 对象描述组件
mountObjectComponent(vnode, container)
}
} function mountElement(vnode, container) {
const el = document.createElement(vnode.tag);
for (const key in vnode.props) {
if (/^on/.test(key)) {
// on 开头是事件
el.addEventListener(
key.substr(2).toLowerCase(), // 事件名 onClick -> click
vnode.props[key] // 事件处理函数
);
}
}
// 处理 children
if (typeof vnode.children === 'string') {
el.appendChild(document.createTextNode(vnode.children));
} else if (Array.isArray(vnode.children)) {
vnode.children.forEach((child) => {
renderer(child, el);
});
} container.appendChild(el);
} function mountFunctionComponent(vnode, container) {
// 获取 vnode
const subtree = vnode.tag();
renderer(subtree, container);
} function mountObjectComponent(vnode, container) {
// 获取 vnode
const subtree = vnode.tag.render();
renderer(subtree, container);
} renderer(vnode, document.body);

模板的工作原理

编译器:模板编译为渲染函数

<div @click="handler">
click me
</div>

编译为

render() {
return h('div', { onClick: handler }, 'click me')
}

Vue 是各模块组成的有机体

模板 --[编译器]--> 渲染函数 --[渲染器]--> 真实DOM

如果在编译器中增加优化,比如静态节点的判断,就可以在渲染器减少一些工作。

《Vue.js 设计与实现》读书笔记(1-3章)的更多相关文章

  1. Javascript高级程序设计读书笔记(第二章)

    第二章  在HTML中使用Javascript 2.1<script>元素 延迟脚本(defer = "defer")表明脚本在执行时不会影响页面的构造,脚本会被延迟到 ...

  2. javascript高级程序设计读书笔记-事件(一)

    读书笔记,写的很乱   事件处理程序   事件处理程序分为三种: 1.html事件2. DOM0级,3,DOM2级别  没有DOM1 同样的事件 DOM0会顶掉html事件   因为他们都是属性  而 ...

  3. Javascript高级程序设计读书笔记(第六章)

    第6章  面向对象的程序设计 6.2 创建对象 创建某个类的实例,必须使用new操作符调用构造函数会经历以下四个步骤: 创建一个新对象: 将构造函数的作用域赋给新对象: 执行构造函数中的代码: 返回新 ...

  4. JavaScript高级程序设计 读书笔记 第一章

    JavaScript是一种专门为与网页交互而设计的脚本语言 JavaScript实现 ECMAscript---核心 DOM---文档对象模型 BOM---浏览器对象模型

  5. Javascript高级程序设计读书笔记(第10章 DOM)

    第10章 DOM 10.1  节点层次 每个节点都有一个nodeType属性,用于表明节点的类型.任何节点类型必是下面中的一个: Node.Element_NODE(1); NODE.ATTRIBUT ...

  6. Javascript高级程序设计读书笔记(第三章)

    第3章 基本概念 3.4 数据类型 5种简单数据类型:undefined.boolean.number.null.string. typeof操作符,能返回下列某个字符串:“undefined”.“b ...

  7. JavaScript高级程序设计 读书笔记 第二章

    <script>元素 直接在页面中嵌入JavaSript代码或包含外部JavaSript文件. 在代码中任何地方不能出现</script>,可通过转义字符'\'解决. 在XHT ...

  8. javascript高级程序设计读书笔记

    第2章  在html中使用javascript 一般都会把js引用文件放在</body>前面,而不是放在<head>里, 目的是最后读取js文件以提高网页载入速度. 引用js文 ...

  9. JavaScript高级程序设计-读书笔记(7)

    第22章 高级技巧 1.高级函数 (1)安全的类型检测 在任何值上调用Object原生的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串. ...

  10. JavaScript高级程序设计 读书笔记

    第一章 JavaScript 简介 第二章 Html中使用JavaScript 第三章 基本概念 第四章 变量,作用域,内存 第五章 引用类型 第六章 面向对象 第七章 函数表达式 第八章 BOM 第 ...

随机推荐

  1. ffmpeg一些笔记: 代码调试数据

    1.AAC,MP3他的解码数据格式不支持,程序中给的是这个AV_SAMPLE_FMT_FLTP,  Screen-Cpature-Recoder的codec-id为AV_CODEC_RAW_VIDEO ...

  2. Hadoop 部署

    hadoop部署步骤: 环境rhel8.2 1.配置主机网络信息 使物理机能和主机ping通 使用secureCRT与虚拟连接 设置网卡(dhcp) [root@maoqiyang ~]# nmcli ...

  3. 【Java】JDBC Part5.1 Hikari连接池补充

    Hikari Connection Pool Hikari 连接池 HikariCP 官方文档 https://github.com/brettwooldridge/HikariCP Maven依赖 ...

  4. 【Java】IDEA普通JavaEE项目实现SSM整合

    一.需要的组件 首先是解决组件问题,非Maven项目构建的jar包 [Servlet & JSP & JSTL] 虽然不是Maven项目,但是JSTL的组件是需要引入的 这里就按照Ma ...

  5. 英语表达中address和solve的区别

    "Address" 和 "solve" 都表示处理问题,但在具体用法和含义上有所不同: Address: 含义: 处理.应对.讨论或提及问题. 强调: 关注并开 ...

  6. Linux系统——删除用户命令

      背景: 负责管理实验室的服务器,近期有保研的大三同学放弃保送到实验室而选择其他实验室,因此需要把之前给他开的账号取消掉. ===================================== ...

  7. 2024全球数字经济大会:大模型时代下DataOps驱动企业数智化升级

    7月5日,以"开源生态筑基础,数字经济铸未来"为主题的2024全球数字经济大会在北京成功举办,来自全国各地的专家学者.企业代表.数据库行业从业人士及众多开源开发者,共聚一堂,共同探 ...

  8. 从论文到图谱,或许只差一个html

    书接上回,在文章<论文图谱当如是:Awesome-Graphs用200篇图系统论文打个样>中,我向大家讲述了如何用图的方式思考图计算系统的演进历史,并在后续的系列文中结合Awesome-G ...

  9. ρars/ey 题解

    给个链接:ρars/ey. 我们考虑一个树上背包. 设 \(f_{u,i}\) 表示在 \(u\) 号节点的子树内删除 \(i\) 个点的最小代价.显然有答案为 \(f_{1,siz_1-1}\). ...

  10. 【CMake系列】01-CMake是什么

    在很多开源项目中,经常可以看到CMakeLists.txt 这一文件,依靠它才能完成项目的配置运行过程.那它是什么? 接下来,在这个专栏中,我们将系统学习CMake这一个重要工具. 本专栏的实践代码全 ...