JS 性能优化
性能优化进阶
Navigation Timing API
面试:在代码执行之前,浏览器加载页面发生了什么?
=> 浏览器原理
=> 广度:DOM 渲染、存储…
打印当前页面耗时:
1 | // index.html |
函数式编程
函数式编程
起源
历程:
命令式(脚本) => 面向对象式
命令式(脚本) => 函数式
解决代码复用的问题
原理特点
什么是函数式原理
加法结合律 | 因式分解 | 完全平方工时
水源 => 组合(水管 + 走线) => 花洒
理论思想
- 一等公民——函数 => 1.逻辑功能最终实现的落脚点 2.实现函数+拼接流程
- 声明式编程
- 惰性执行-衔接性,性能节约
实际开发
1.纯函数改造
1 | const _class = { |
2.流水线组装-加工&组装
- 加工 - 科里化
1 | // f(x,y,z) => f(x)(y)(z) |
面试题
手写构造可拆分传参的累加函数
add(1)(2)(3)(4)
1 | // 构造科里化结构 |
- 流水线 - 组装函数
1 | const compose = (f, g) => (x) => f(g(x)) |
常见的三方库
lodash
rxjs
浏览器 Browser
本文字数: 2.8k 阅读时长 ≈ 3 分钟
test
本文字数: 4 阅读时长 ≈ 1 分钟
test
vue-cli 详解
vue-cli
- 基础:用于生成项目文件体系的搭建 + 用户交互
- metadata 配置(元数据)
- parser & render
vue-cli_2.x.x
/bin/vue-init 前置工作
1 | // 下载远程仓库 => 远程拉去github内的配置 |
面试题:如何使用本地模板,预设模板 而不是 github?
使用 –offline
如何获取用户参数
vue init webpack zhaowa-app
program.args[0] => ‘webpack’
// 是否包含斜杠 => 路径层级 =>非默认预制模板
const hasSlash = template.indexOf(‘/‘)>-1
// 项目名称
rawName = program.args[1]
//输入是否为空 => 是否以当前文件目录作为项目根目录
const inPlace = !rawName || ‘.’
//调整当前目录作为构建目录的根路径
const name = inPlace ….
//本地目录模板仓库路径拼接 /zhaowa/.vue-templates/webpack
const tmp = path.join(home,’…’)
/lib/generate.js
1 | // 静态网页文件生成器 |
/lib/ask.js
解析传进来的模板有哪些要询问的
inquirer.prompt
/lib/filter.js 过滤不需要的
vue-cli_3.x.x
/lib/create.js
1 | const creator = new Creator(name, targetDir, getPromptModules()) |
/lib/Creator.js
1 | module.exports = class Creator extends EventEmitter {} |
流程
用户创建指令 -> 创建参数解析 -> 加载模板(远端/本地) – prompts –> 处理文件路径 -> 文件层级处理 -> 文件模板渲染(plugins) -> 产出包
如何书写 node 脚本工具
vue3.x 源码
vue2.x 源码
引言
面试:观察者模式 & 发布订阅
观察者模式:(观察者,被观察者) 中心一对多 + 系统单点的灵活和拓展
发布订阅:(发布者,订阅者,发布订阅中心) 调度中心 => 将注册列表遍历然后发布给订阅者
view -> listner/binding/处理内容 -> model
追问:要实现这些方式,如何双向绑定
数据监听器Observe <---- mvvm
| |
| |
V |
通知数据变化Dep |
| ↑ |
| 添加订阅 |
V | |
连接双方的桥梁watcher<--- 代码生成(指令归纳)
| | |
| 绑定函数/订阅数据 |
更新视图 | |
| -------- |
V V
view <—更新视图— compiler
源码 -> 原理 -> 他人源码思路
vue进阶
vue 进阶
特征一:模块化 => vue-template-compiler (编译态把 template 转换成 render())
插槽 - 面试考察点 => 对比形式
默认插槽
组件外部维护参数与结构,内部安排位置摆放
- 追问 => 默认插槽的实现方式》 => 插槽聚合(渲染在一个地方 顺序渲染)
- 追问 => 多个插槽会以何种形态渲染(合并) => 如何放在不同的地方?
具名插槽
用 name 表示当前身份,从而在组件内部区分
1 | // 父组件 |
- 具名插槽可以在指定位置分开布局 => 原理:name 索引了一段单个解析的命名空间,node 独立由这个单个解析空间进行渲染
- 追问 => 以 node 渲染为单位 => 混合式传参?
作用域插槽
1 | // 父组件 |
外部可以做结构勾勒和参数合并,内部也可以提供参数混合
- 父子参数共同向 slot 传递
模板的二次加工
- watch | computed => 配置里声明和书写
- 其余方法:
a. 函数 - 过滤器 | 独立管道符 => 管道符和函数有什么区别?| 管道符能拿到实例嘛? (不能!)
b. v-html => 递归调用渲染 node => 安全性风险
c. 利用组件形式
1 | // 过滤器 |
jsx 更自由的 all in js
- 面试题:
- 语法糖的实现
- jsx 的优点和劣势
- vue 编译:(_beforeMount_)template => render() => (_Mounted_)vm.render()
- template 编译,带有 dom 渲染优化,性能节约
- 直接写 render 函数不受 vue 语法限制,不依赖于 vue 的 api
特征二:组件化
1 | Vue.component('component', { |
- 抽象复用
- 精简 & 聚合
混入 mixin - 逻辑混入
- 应用:公共逻辑功能的继承
- 面试:合并策略 生命周期
- 变量补充形式上 => 额外补充、不会覆盖
- 生命周期 => minxin 在引用该 mixin 组件之前执行
- 同样引用的两个 mixin => 根据引用顺序安排加载顺序
继承拓展 extends - 逻辑上的共同拓展
- 核心逻辑的继承
- 合并策略
- 不会覆盖
- 生命周期 => 不论是业务代码还是 mixin 都在 extents 生命周期之后
- 只有一个
插件系统
1 | import element from 'element' |
Vue 3 - compositionAPI
vue 基础 v5
vue 基础
理论
面试题:对 MVVM 的了解
- Web 应用发展史
- 语义化模板
- MVC - model view controller
- MVVM - model view viewModel
- 数据本身会通过 model 挂在在 viewModel,vm 会劫持数据并同步至渲染层
- 视图层发生外部变化,会同样回调给 vw,返回给 model
写法
vue 如何利用 mvvm 开发?
数据双向绑定
- 利用花括号,构筑了数据与 vm 的双向绑定关系 =》 buildTemplate | compile
- 通过视图绑定监听事件来处理数据 =》v-model === :value @input => 节点处理流程
buildTemplate =》 render()
生命周期
面试题:vue 的生命周期
创建阶段: beforeCreate => created => beforeMount => mounted
更新阶段: beforeUpdate => updated
销毁阶段: beforeDestroy =》 destroyed
beforeCreate: new Vue() - 创建实例阶段
created: data | props | method | computed - 数据创建
beforeMount: vDom(虚拟节点) - 数据操作以及虚拟 dom 的变化 但不能涉及 dom
mounted: Dom 更新
beforeUpdate: vDom - 完成更新,dom 还未更新
updated: dom 完成更新 =》 谨慎做更新数据操作
beforeDestroy:实例尚未销毁 - 清空 eventBus setTimeOut
destroyed:完全销毁
补充:key =》 diff =》 dom diff =》 节点 id
监听
面试题:computed 和 watch
相同点:
- 基于 vue 的依赖收集机制进行采集
- 都是被依赖的变化所触发,从而进行处理回调
不同点:
- 入/出:computed 多入单出,watch 单入多出
- 性能:computed 存在缓存,不收调用次数的性能损耗;watch 只在监听的值变化时,不包含生成 immediate
- computed 关注结果,watch 关注过程
问:computed 缓存和响应式如何实现的?
完整过程:
- 流程:new Vue() => 初始化 computed(initState) => createComputedGetter(key) => mount
- 劫持:getter 属性变化区分是否是最新状态 dirty
- target depend <==> 原值和依赖之间的关系链
指令 & 条件
条件
v-if | v-show
v-else | v-else-if
v-for
v-for & v-if 在同一节点使用时
vue2.x v-for 会优先作用
vue3.x v-if 总是优先于 v-for
v-model v-once v-text v-html v-bind
自定义指令
事件 - v-on
修饰符
.stop .prevent .once .capture .self .passive
事件的设计 - 为何 vue 把事件设计在模板上而不是 js 中
- 模板定位视图绑定的触发源 + 触发源寻找触发事件的逻辑 —— 方便定位
- js 与视图绑定解耦 —— 更便于测试隔离
- vm 销毁,自动解绑事件 —— 便于回收