随笔(一)
随笔(一)
最近在看面试八股文,有点无聊,重新回顾了一下生疏的知识点。
一. websocket
1. 基本介绍与对比
一种基于TCP的应用层协议,浏览器与服务器只需一次握手即可持久连接,进行全双工通讯。
其实就是客户端通知服务器哪些ID的客户端可以处理事件。
特点:服务器可以向客户端主动推动消息,客户端也可以主动向服务器推送消息。
缺点:在服务器端配置比较复杂。
对比:短轮询:每隔一段时间就发送请求,浪费资源;长轮询:服务端收到请求,挂起;SSE:使用流信息让服务器向客户端推送信息。
2. 多tab页通信
前端现在常常流行SPA,页面切换基于vue-router,如果逻辑复杂,处理会很麻烦,所以有的功能会利用MPA,那就存在浏览器多tab页通信问题,解决方案如下:
- localStorage:同源共享策略,将需要共享的信息通过setStorage(name, val)的方式存储,获取只需监听store事件即可。【同源共享,但存储大小有限制】
- websocket:websocket最大的特点就是全双工通信,利用此特点,建立第三方服务器,让每个tab页成为客户端,建立通信。当一个tab页进行信息更新,直接send即可,接着让服务器进行共享信息广播(除进行更新的tab页)。【推荐用于跨域共享】
- shareWorker:由于js是单线程的,针对此出现了webWorker,而shareWorker就是其中的一种。机制与websocket一致,但是是非跨域。某个tab页通过postMessage更新信息,其他tab页借onMessage监听共享信息。【兼容性不好】
- cookie+setInterval:古老方法,共享信息存入cookie,但是cookie没有store的监听机制,需要通过如setInterval这种方法模拟轮询机制,进行信息广播。【存储大小有限制,消耗性能】
3. 跨域
JSONP:利用script标签不受跨域限制,将带有callback参数的GET请求嵌入。【只支持GET请求】
CORS:跨域资源共享机制。实施需要服务器进行相关配置,后端设置响应头Access-Control-Allow-Origin(表示哪些域名可以访问资源)。
浏览器访问需要判断是简单请求还是非简单请求,条件是:
- GET/POST/HEAD
- Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(application/x-www-form-urlencoded、multipart/form-data、text/plain)
非简单请求发送之前需要发送预检请求(OPTIONS)进行嗅探,询问服务器可访问范围。
代理转发
原理:同源策略只是浏览器对安全的限制,而服务器之间没有同源策略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd(), '')
return {
plugins: [
vue()
],
server: {
host: '0.0.0.0',
port: env.VITE_APP_PORT,
proxy: {
'/api': {
target: env.VITE_APP_API_BASEURL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
}
}
}
});本地开发这里就用到代理,浏览器通过配置server,将实际请求转到本地服务,再转发到后端地址。
最终代码打包会通过如nginx来实现。
postMessage
H5新增的跨文档消息传递机制
websocket
二、webpack
首先得了解页面渲染过程,首先源代码parse AST,接着使用diff对AST进行操作,最后将修改后的AST generate。这里涉及到JS语言是解释性的原因,C/Java等都是直接转成二进制文件进行运行。
如今都是将AST转成字节码进行编译,但是以前都是直接通过解释器对AST进行展示。
所以可以在AST—>结果之间加入工具(多一个步骤进行操作)
1. Babel
是source to source的转换,常用功能如ES6转ES5、缺失特性处理、源码转换、taro编译等。
分为三个阶段:
- parse:源代码—>AST
- transform:遍历AST,使用visitor访问节点,进行增删改,返回新的AST
- generate:AST—>目标代码字符串,同时生成sourcemap(源码到目标代码的转换关系),这玩意用来调试
AST的公共属性有:type、start、end(源码起始位置)、loc、leadingComments、innerComments、trailingComments、extra(额外信息)
API:parser、traverse、visitors、generator(含sourcemaps:true)、code-frame(标记代码位置)
babel-auto-tracker:埋点,可以监控函数执行效率。
polyfill:Babel虽然说是对ES6进行5的转化,但这只是语法层面,api层面需要ployfill。
2. webpack
使用原因:执行效率,不打包基础支持不够。
打包方式:
- 把js、css、image看作一个模块,用import/require引入
- 找到entry,通过entry找到依赖文件,将其打包在一块
- 将最终的bundle文件拆分,异步按需加载
- 一个文件多处引用,也仅打包为一个文件
- 多个entry中如果有相同代码,可以用插件抽离
具体过程描述一下:首先通过入口文件创建chunk,默认名字叫main;接着进入模块文件(根据entry地址),逐一转换文件代码,具体过程为:chunk中创建模块记录表(模块id也就是文件绝对路径+转换后的代码),每次转换前看一下表有没有转换过,如果没有,就读取文件内容,语法分析形成AST,记录依赖保存到dependencies中,替换依赖函数,将转换的代码放入模块记录表里面。
loader
由于webpack只支持JS和JSON,可以通过loader去支持其他文件类型并进行转换。
loader本质是一个函数,接收源文件作为参数,返回转换的结果。
名称 描述 babel-loader 转换ES6、ES7等新语法 style-loader 将css通过style标签放进html的head里 css-loader 支持.css文件加载解析 less-loader 将less转换成css ts-loader 将ts转换成js file-loader 进行图片、字体的打包 raw-loader 将文件以字符串导入 thread-loader 多进程打包JS、CSS,与happypack一样 加载解析less
1
2
3
4
5
6
7
8module: {
rules: [
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
},
]
}解析ES6
1
2
3
4
5
6
7
8
9module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/ //不在这个文件夹中寻找
},
]
}版本区别
在webpack5之前,读取文件需要借助raw-loader、url-loader、file-loader。5就直接通过资源类型模块(asset module type)来替换。
5 5之前 作用 assert/resource file-loader 将文件发送到输出目录 assert/inline url-loader 导出资源data url assert/source raw-loader 导出文件源代码 assert 举例子说一下吧,比如图片加载,我们推荐外部引用使用link,内部直接资源内联即可。这种切换标准可以在assert中设置图片大小maxsize,如果小于maxsize,直接将图片转为base64进行嵌入img src中。
插件
作用:用于bundle文件优化,资源管理和环境变量注入,作用在整个构建过程。
常用插件 作用 HtmlWebpackPlugin 将输出的css/js等套入html模板内 CleanWebpackPlugin 清理dist目录 ExtractTextWebpackPlugin 提取css uglifyjsWebpackPlugin 压缩JS CommonsChunkPlugin build之后js文件夹里面那些公共js mode
有三种:development、production、none
3. 文件监听
文件监听:源码发生变化,自动重新构建出新的输出文件。
webpack开启监听方法:
启动webpack,带上–watch,本质就是轮询,所以不建议采用【每次要手动刷新浏览器】
配置webpack.config.js中设置watch:true
此种方法就是HMR热更新,目的是做到不用刷新浏览器而将新变更的模块替换旧模块。
1
2
3
4
5
6module.exports = {
...
devServer: {
hot: true,
}
}npm run server
runtime可以理解为js运行环境
这里可能涉及到文件指纹,就是文件名加个base后缀,判断文件是否有改动。
4. 代码压缩
针对的主要就是html、css、js文件进行压缩。
| 插件 | 使用 |
|---|---|
| Html-minimzer-webpack-plugin | new HtmlMinimzerPlugin() |
| css-minimzer-webpack-plugin | new CssMinimzerPlugin() |
| terser-webpack-plugin | new TerserPlugin() |
5. 小程序适配
这些插件的使用让我想起之前做学校答题小程序多端适配问题,网上的解决方案有什么用em/rem,这种开发的时候贼麻烦,其实还是可以使用px完成本地开发,然后用px2rem-loader和lib-flexible(淘宝的库)实现多设备同步。
但是会遇到一个问题,lib-flexible是个js文件,需要引入,但是webpack打包的时候,script标签是在最后面的,这样无法自动转换(如font-size),影响渲染效果。
解决方案:使用资源内联方法
1 | <script> |
raw-loader以字符串导入文件,babel-loader针对ES6的语法兼容问题。
6. 项目打包
SPA页面渲染是生成AST,在框架加载完毕,才将html/css等样式渲染上去,不利于搜索引擎抓包,为此出现了SSR(vue用的是Nuxt.js)等概念,都是为了SEO优化。
针对MPA打包,原理就是通过遍历入口文件(Object.keys(entryFiles)),对每个页面使用HtmlWebpackPlugin将各页面样式套入模板内,导出入口、数组(存放加载完的页面)。
DLL的目的是提前对基础库进行打包,加快build速度,但是实际情况vue-cli等都是关闭的,因为dll需要提前配置,不一定效益成正比。
这里就需要提到一个问题,我之前的管理平台为啥使用vite,而不是webpack进行打包。vite内部借助Esbuild来提升性能(Esbuild是用go开发,多线程打包,代码直接变为机器码),而webpack打包过程中存在众多resolve、loader、parse、transform等,都需要js来操作,而js本身就是解释性语言,需要编译,调试还是单线程。
1 | const res = await esbuild.tansform(code, options) //将code转化为指定格式的内容 |
vite利用Esbuild来进行预构建和内容转换,其中预构建目的是 将非ESM规范代码转换、将第三方依赖内部的多个文件合并为一个,减少http请求数量。
这个收集第三方依赖的过程:解析模块的路径,触发onResolve hook,判断是第三方依赖还是业务代码,最终所有文件都在 /node_modules/.vite/deps 中。
vite本质和webpack差不多,第一步createAssets收集和处理文件代码,vite借助esbuild,而webpack里面借助Babel;第二步createGraph创建文件依赖图;第三步bundle,输出bundle.js文件。
三、项目规范
1. 项目规范
项目的规范还要有测试(单元测试、冒烟测试等)、git规范、changelog文档
git常用命令如下:
1 | git pull |
解决冲突问题:
两分支修改同一文件:
当前分支直接修改代码,然后提交即可
两分支修改了同一个文件名字:
本地当前分支上,修改冲突代码,push(记得要沟通)
四、项目优化
1. vue性能优化
编码角度
不要把数据都放在data中;
keep-alive缓存组件;
尽可能拆分组件,提高复用率;
key值唯一;
路由懒加载;
数据持久化存储尽量用防抖、节流;
加载优化
按需加载;
内容懒加载;
图片懒加载;
用户体验
骨架屏;
SEO优化
预渲染;
服务端ssr;
打包优化
多线程打包(vite);
CDN形式加载第三方模块;
抽离公共文件;
2. 首屏优化
- 使用路由懒加载;
- 非首屏组件使用异步组件;
- 首屏不重要的组件延迟加载;
- 减少首屏js\css文件大小;
- 尽量减少DOM的数量和层级;
- 精灵图;
- 图片懒加载;
3. vue3优化
vue3为啥性能比2好,讨论前首先需知道两者区别。
2 VS 3
2数据劫持用的是object.defineProperty,3用的是proxy,实现对所有对象的监听,无需对数组重写方法;
3支持framegrament,可以有多个根节点;
2用的是选项式api,3是组合式api;
生命周期不同,3直接setup;
2可以用原型,3是工厂函数;
性能优势
diff算法的优化(加了静态标记);
静态提升(对没有变化的元素只渲染一次,后面复用);
事件监听缓存;





