@gyyin
2022-07-30T16:21:35.000000Z
字数 4278
阅读 210
面试
最重要的是复习这几块的内容:
fiber 是 react16 新的架构,支持优先级调度,和以前的区别主要在于,以前的是栈递归,边做 diff 边更新,会导致页面长时间无响应。
fiber 是一个链表结构,通过 return、child、siblings 这些来连接起整个虚拟 DOM。每个虚拟 DOM 节点会创建一个 fibe。
第一次渲染的时候,会先创建一个空的 RootFiber 节点,基于这个 RootFiber 节点开始创建一个 WorkInProgress 树,WIP 树会根据虚拟 DOM 自顶向下创建 Fiber 结构,最终创建了一个 Fiber 树,这个时候会标记 effectTag。这个阶段一般是协调。
这一阶段是可以被打断的,如果当前桢剩余时间不足了,那么就不会继续了,等下一桢有足够时间后继续做递归。
协调里面也有两个阶段,一个是『递』,这是一个深度优先遍历,会一直往下找到叶子节点为止,然后开始『归』,寻找兄弟节点,一直找到其叶子节点,如果没有兄弟节点了,就开始往上回溯,回溯的时候会通过一个effect链表,将有 effectTag 的节点串联起来,然后一直回溯到 RootFiber 节点。
这个时候开始 commit 阶段,这个时候会根据在递归的时候的 effectTag 链表开始做 DOM 插入,这里会从链表头节点一直到链表末尾,这里一口气更新好 DOM 节点。很多事情都是在这个阶段做,比如执行 useEffect、componentDidMount、componentDidUpdate。
在递归阶段执行 setState 的时候,会把它放到一个队列里面,至于要不要立即更新,这里做了判断,需要判断当前是否需要批量更新,不需要就不更新,等 commit 阶段再去更新。
但是如果 setState 放到异步任务里面,这里就会出现问题,commit 阶段已经更新完了,这个时候才会 setState,就会判断立即更新,所以不管是用 Promise.resolve、async/await、setTimeout 等等,都会导致 setState 立即更新。
Expires、cache-control
Last-Modified、Etag
转义、CSP
httpOnly、sameSite、referer、下发token
设置 IP 黑名单
HTTP 状态码、请求头、HTTP1.1、HTTP2、HTTP3、HTTPS
Fastify、流、中间件、事件循环、多进程
babel-loader 来转换各种语法,其中 @babel/preset-react 可以转换 jsx 的语法,它包括了 @babel/plugin-syntax-jsx、@babel/plugin-transform-react-jsx、@babel/plugin-transform-react-display-name 三个插件。
babel-loader 可以设置 cacheDirectory,下次构建的时候可以从缓存中读取数据,提高构建速度,一般在 node_modules/.cache/babel-loader 文件夹下面。
如果很慢的话,需要写更精确的正则匹配,还要排除 node_modules,在 exclude 里面配置。
@babel/env 是转换 ESNext 语法的,stage 阶段的无法转换需要特别安装 preset-stage 插件。
@babel/polyfill 体积过大,目前我们项目里面都用的是 core-js,体积更小,按需引入。
一般可以打包多个页面,使用 html-webpack-plugin,设置多个 entry,这里的 plugin 可以选择某几个 entry 作为 chunk 依赖,可以实现首页只加载关键资源。
output 里面可以设置打包后文件的地址,一般是 html 里面的文件资源地址,这里可以选择 CDN 的地址。
filename 一般是指 entry 里面我们要打包出来的文件名,chunkFilename 是指不在我们 entry 里面,却又要打包出来的文件,一般就是懒加载的和公共第三方库。
output 里面还可以设置 libraryTarget 和 library,一般是用于打包第三方类库使用的,libraryTarget 可以选 commonjs、umd、amd 等规范,library 则是设置暴露出来的变量名。
但是 webpack 打包出来的会有一些无用的代码,所以我这里一般使用 microbundle 或者 rollup 来打包纯 JS SDK。
处理 CSS 一般使用 mini-css-extract-plugin 这个插件来处理,可以进行压缩,参数和 output 里面类似,filename 和 chunkFilename,代表含义也是一样的。
css-loader 里面可以设置 options 来实现 css-modules。
modules: {
localIdentName: '[name]__[local]___[hash:base64:5]'
}
一般在 module.rules 下面去编写,使用 test 来编写一个正则匹配文件名,use 一般传一个数组,数组里面可以是字符串(babel-loader),也可以是一个对象,包括 loader、options 属性,这里可以传入参数给 loader 进行处理。
一般为了避免线上浏览器缓存,对打包后的文件后缀添加hash,hash分为hash、chunkhash、contenthash,hash是项目中所有文件共享一个hash,只要一个文件改变了,其他的文件后缀也会变。
chunkhash 是针对一个 chunk,但如果 JS 文件变了,依赖的 css 文件后缀也会变。
contenthash 是目前使用最多的,也是最优的,js 和 css 是分离的。
这是一个数组,可以接受多个 options,可以用自带的,也可以用 terser-webpack-plugin 来配置压缩、缓存、parallel。
参数 chunks 支持三个,分别是 async、initial、all。
async 的意思是只从动态加载的模块拆分,意味着如果不是动态加载的模块里面的第三方库和引入,这个是不会拆分 chunk 文件的。
initial 意思是只从入口文件拆分,意味着不是入口文件,也不会进行拆分。
all 表示两个都支持,动态加载的文件和入口文件都会拆分。
runtimeChunk是将包含 chunks 映射关系的 list 单独提取出来,不然的话每次改动都会重新生成hash,导致runtimeChunk变化,进而导致包含它的 app.js 变化,这里单独提取出来,有利于 app.js 缓存。
script-ext-html-webpack-plugin 支持把 JS 直接内联到 HTML 里面,有利于一些文件不用重复加载,比如 runtimeChunk 每次构建后hash都会变化。
cacheGroups 是用来对 chunk 进行拆分的规则,常用的属性是 chunks 和 priority、test,chunks是按什么规定拆分,priority是拆分的优先级,test是拆分的文件匹配规则。
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};
historyApiFallback: {
// 使用正则匹配命中路由
rewrites: [
// /user 开头的都返回 user.html
{ from: /^\/user/, to: '/user.html' },
{ from: /^\/game/, to: '/game.html' },
// 其它的都返回 index.html
{ from: /./, to: '/index.html' },
]
}
可以用 file-loader 和 url-loader,但是 url-loader 是转换成 base64,可能导致体积过大,应该在 options 里面设置 limit 和 fallback。
链表、树、图、动态规划
Admin、权限系统、H5 项目
雪碧图、webp、base64、图片懒加载
DNS 预解析、资源预加载、只加载关键资源、资源懒加载、服务端渲染、
利用 husky(git的钩子)和 lint-staged(过滤暂存区文件,避免检查整个项目文件)来做commit前的代码处理,当然格式化校验还是用 eslint 和 prettier,一般是 eslint --fix 和 prettier --write。
Webpack、Jenkins、Docker
Auth 设计、运维、监控,h5pay 访问量、h5ssr 设计、Jenkins 部署构建
目前还需要多补上的一个是性能优化,包括web和nodejs,一个是监控方面的,比如定位内存泄露。
一个是