结尾
正式学习前端大概 3 年多了,很早就想整理这个书单了,因为常常会有朋友问,前端该如何学习,学习前端该看哪些书,我就讲讲我学习的道路中看的一些书,虽然整理的书不多,但是每一本都是那种看一本就秒不绝口的感觉。
以下大部分是我看过的,或者说身边的人推荐的书籍,每一本我都有些相关的推荐语,如果你有看到更好的书欢迎推荐呀。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
- 当
f5
刷新网页时,跳过强缓存,但是会检查协商缓存;
强缓存
-
Expires
(该字段是http1.0
时的规范,值为一个绝对时间的GMT
格式的时间字符串,代表缓存资源的过期时间) -
Cache-Control:max-age
(该字段是http1.1
的规范,强缓存利用其max-age
值来判断缓存资源的最大生命周期,它的值单位为秒)
协商缓存
-
Last-Modified
(值为资源最后更新时间,随服务器response返回,即使文件改回去,日期也会变化) -
If-Modified-Since
(通过比较两个时间来判断资源在两次请求期间是否有过修改,如果没有修改,则命中协商缓存) -
ETag
(表示资源内容的唯一标识,随服务器response
返回,仅根据文件内容是否变化判断) -
If-None-Match
(服务器通过比较请求头部的If-None-Match
与当前资源的ETag
是否一致来判断资源是否在两次请求之间有过修改,如果没有修改,则命中协商缓存)
浏览器是如何渲染网页的
- 参考:浏览器渲染页面过程[2]
重绘(Repaint)和回流(Reflow)
重绘和回流会在我们设置节点样式时频繁出现,同时也会很大程度上影响性能。
-
重绘:当节点需要更改外观而不会影响布局的,比如改变
color
就叫称为重绘 -
回流:布局或者几何属性需要改变就称为回流。
-
回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变父节点里的子节点很可能会导致父节点的一系列回流。
以下几个动作可能会导致性能问题:
-
改变
window
大小 -
改变字体
-
添加或删除样式
-
文字改变
-
定位或者浮动
-
盒模型
重绘和回流其实也和 Eventloop
有关。
-
当
Eventloop
执行完Microtasks
后,会判断document
是否需要更新,因为浏览器是60Hz
的刷新率,每16.6ms
才会更新一次。 -
然后判断是否有
resize
或者scroll
事件,有的话会去触发事件,所以resize
和scroll
事件也是至少16ms
才会触发一次,并且自带节流功能。 -
判断是否触发了
media query
-
更新动画并且发送事件
-
判断是否有全屏操作事件
-
执行
requestAnimationFrame
回调 -
执行
IntersectionObserver
回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好 更新界面 -
以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行
requestIdleCallback
回调
如何减少重绘和回流:
-
使用
transform
替代top
-
使用
visibility
替换display: none
,因为前者只会引起重绘,后者会引发回流(改变了布局) -
不要把节点的属性值放在一个循环里当成循环里的变量
-
不要使用
table
布局,可能很小的一个小改动会造成整个table
的重新布局 -
动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用
requestAnimationFrame
-
CSS
选择符从右往左匹配查找,避免节点层级过多 -
将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于
video
标签来说,浏览器会自动将该节点变为图层。 -
避免使用
css
表达式(expression
),因为每次调用都会重新计算值(包括加载页面) -
尽量使用
css
属性简写,如:用border
代替border-width
,border-style
,border-color
-
批量修改元素样式:
elem.className
和elem.style.cssText
代替elem.style.xxx
-
需要要对元素进行复杂的操作时,可以先隐藏(
display:"none"
),操作完成后再显示 -
需要创建多个
DOM
节点时,使用DocumentFragment
创建完后一次性的加入document
-
缓存
Layout
属性值,如:var left = elem.offsetLeft;
这样,多次使用left
只产生一次回流
设置节点为图层的方式有很多,我们可以通过以下几个常用属性可以生成新图层
-
will-change
-
video
、iframe
标签
首屏加载优化方案
-
Vue-Router路由懒加载(利用Webpack的代码切割)
-
使用CDN加速,将通用的库从vendor进行抽离
-
Nginx的gzip压缩
-
Vue异步组件
-
服务端渲染SSR
-
如果使用了一些UI库,采用按需加载
-
Webpack开启gzip压缩
-
如果首屏为登录页,可以做成多入口
-
图片懒加载减少占用网络带宽
-
页面使用骨架屏
-
利用好script标签的async和defer这两个属性。功能独立且不要求马上执行的js文件,可以加入async属性。如果是优先级低且没有依赖的js,可以加入defer属性。
可利用performance.timing
看各个步骤的耗时:白屏时间:performance.timing.responseStart \- performance.timing.navigationStart
二、html
html5有哪些新特性、移除了那些元素?
新增功能:HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加
-
新增选择器 document.querySelector、document.querySelectorAll
-
拖拽释放(Drag and drop) API
-
媒体播放的 video 和 audio
-
本地存储 localStorage 和 sessionStorage
-
离线应用 manifest
-
桌面通知 Notifications
-
语意化标签 article、footer、header、nav、section
-
增强表单控件 calendar、date、time、email、url、search
-
地理位置 Geolocation
-
多任务 webworker
-
全双工通信协议 websocket
-
历史管理 history
-
跨域资源共享(CORS) Access-Control-Allow-Origin
-
页面可见性改变事件 visibilitychange
-
跨窗口通信 PostMessage
-
Form Data 对象
-
绘画 canvas
移除的元素:
-
纯表现的元素:basefont、big、center、font、 s、strike、tt、u
-
对可用性产生负面影响的元素:frame、frameset、noframes
viewport
延伸提问:怎样处理 移动端 1px 被 渲染成 2px问题?
-
局部处理
-
meta标签中的 viewport属性 ,initial-scale 设置为 1
-
rem按照设计稿标准走,外加利用transfrome 的scale(0.5) 缩小一倍即可;
-
全局处理
-
mate标签中的 viewport属性 ,initial-scale 设置为 0.5
-
rem 按照设计稿标准走即可
html文档解析
- 参考:html文档解析为AST语法树[3]
三、css
1. css选择器优先级
!important > inline > id > class > tag > * > inherit > default
-
!important:大于其他
-
行内:1000
-
id选择器:100
-
类,伪类和属性选择器,如.content:10
-
类型选择器和伪元素选择器:1
-
通配符、子选择器、相邻选择器:0
同级别的后写的优先级高。
相同class样式,css中后写的优先级高,和html中的class名字前后无关
2. 水平垂直居中
-
文本水平居中:
text-algin: center
-
文本垂直居中:
line-height
等于容器height
;display: flex; algin-items: center;
-
div水平居中:
-
margin: 0 auto;
-
已知父元素宽度:margin-left: width / 2; transform: tranlateX(-50%)
-
未知父元素宽度:position: absolute: top: 50%; transform: tranlateY(-50%)
-
display: flex; justify-content: center;
div垂直居中:
-
已知父元素高度:margin-top: height / 2; transform: tranlateY(-50%)
-
未知父元素高度:position: absolute: top: 50%; transform: tranlateY(-50%)
-
display: flex; algin-items: center;
3. 移除inline-block间隙
-
移除空格
-
使用margin负值
-
使用font-size:0
-
letter-spacing
-
word-spacing
4. 清除浮动
浮动的影响:(1)由于浮动元素脱离了文档流,所以父元素的高度无法被撑开,影响了与父元素同级的元素 (2)与浮动元素同级的非浮动元素会跟随其后,因为浮动元素脱离文档流不占据原来的位置 (3)如果该浮动元素不是第一个浮动元素,则该元素之前的元素也需要浮动,否则容易影响页面的结构显示 清除浮动的3个方法:
- 使用
clear: both
清除浮动
在浮动元素后面放一个空的div标签,div设置样式clear:both来清除浮动。它的优点是简单,方便兼容性好,但是一般情况下不建议使用该方法,因为会造成结构混乱,不利于后期维护。
- 利用伪元素
after
来清除浮动
给父元素添加了:after伪元素,通过清除伪元素的浮动,达到撑起父元素高度的目的
.clearfix:after{
content: “”;
display: block;
visibility: hidden;
clear: both;
}
- 使用CSS的
overflow
属性
当给父元素设置了overflow样式,不管是overflow:hidden或overflow:auto都可以清除浮动只要它的值不为visible就可以了,它的本质就是建构了一个BFC,这样使得达到撑起父元素高度的效果
- 参考:css清除浮动[4]
5. (外)边距重叠
布局垂直方向上两个元素的间距不等于margin的和,而是取较大的一个
- 同级相邻元素
现象:上方元素设置margin-bottom: 20px
,下方元素设置margin-top: 10px
,实际的间隔是20px
避免办法:同级元素不要同时设置,可都设置margin-bottom或margin-top的一个,或者设置padding
- 父子元素
现象:父元素设置margin-top: 20px
,下方元素设置margin-top: 10px
,实际的间隔是20px
避免办法:父元素有padding-top,或者border-top。或者触发BFC
6. 三栏布局
要求:左边右边固定宽度,中间自适应
float
position
flex
7. BFC
BFC
是Block Formatting Context
,也就是块级格式化上下文
,是用于布局块级盒子的一块渲染区域。
简单来说,BFC 实际上是一块区域,在这块区域中遵循一定的规则,有一套独特的渲染规则。
文档流其实分为普通流
、定位流
和浮动流
和三种,普通流其实就是指BFC中的FC,也即格式化上下文
。
普通流:元素按照其在 HTML 中的先后位置从上到下、从左到右布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行。
格式化上下文:页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用
§ BFC的几条规则: 1)BFC 区域内的元素外边距会发生重叠。
2)BFC 区域内的元素不会与浮动元素重叠。
3)计算 BFC 区域的高度时,浮动元素也参与计算。
4)BFC 区域就相当于一个容器,内部的元素不会影响到外部,同样外部的元素也不会影响到内部。
§ BFC的应用:
-
清除浮动:父元素设置overflow: hidden触发BFC实现清除浮动,防止父元素高度塌陷,后面的元素被覆盖,实现文字环绕等等。
-
消除相邻元素垂直方向的边距重叠:第二个子元素套一层,并设置overflow: hidden,构建BFC使其不影响外部元素。
-
消除父子元素边距重叠,父元素设置overflow: hidden
§ 触发BFC的方式:
-
float 不为 none,浮动元素所在的区域就是一个 BFC 区域。
-
position 的值不是 static 或 relative 的元素所在的区域就是一个 BFC 区域
-
display为 table-cell 的表格单元格元素所在的区域也是一个 BFC 区域
-
overflow 不为 visible 的元素所在的区域也是一个 BFC 区域
- 参考:CSS 中你应该了解的 BFC[5]
8. flex布局
弹性布局,Flex 布局将成为未来布局的首选方案。 兼容性:
-
Webkit 内核的浏览器,必须加上-webkit前缀。
-
ie9不支持
基本概念:
-
容器&项目:采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。
-
主轴&交叉轴:堆叠的方向,默认主轴是水平方向,交叉轴是垂直方向。可通过
flex-derection: column
设置主轴为垂直方向。
容器属性:
-
display: flex
-
flex-direction:主轴的方向(即项目的排列方向),row | row-reverse | column | column-reverse;
-
flex-wrap:是否换行,nowrap | wrap | wrap-reverse;
-
flex-flow:direction 和 wrap简写
-
justify-content:主轴对齐方式,flex-start | flex-end | center | space-between | space-around;
-
align-items:交叉轴对齐方式,flex-start | flex-end | center | baseline | stretch;
-
align-content: 多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。flex-start | flex-end | center | space-between | space-around | stretch;
项目的属性:
-
order:项目的排列顺序,数值越小,排列越靠前,默认为0。
-
flex-grow:放大比例,默认为0,指定元素分到的剩余空间的比例。
-
flex-shrink:缩小比例,默认为1,指定元素分到的缩减空间的比例。
-
flex-basis:分配多余空间之前,项目占据的主轴空间,默认值为auto
-
flex:grow, shrink 和 basis的简写,默认值为0 1 auto
-
align-self:单个项目不一样的对齐方式,默认值为auto,auto | flex-start | flex-end | center | baseline | stretch;
-
参考:Flex 布局教程:语法篇 \- 阮一峰[6]
9. CSS动画
1. transition过渡 将变化按照设置的时间长度缓慢执行完毕,而不是立即执行。
delay
的真正意义在于,它指定了动画发生的顺序,使得多个不同的transition可以连在一起,形成复杂效果。
transition的值是简写,扩展开依次是:
transition-property:过渡属性
transition-duration:过渡时间长度
transition-delay:延迟几秒执行
transition-timing-function
-
linear:匀速
-
ease-in:加速
-
ease-out:减速
-
cubic-bezier函数:自定义速度模式,最后那个cubic-bezier,可以使用工具网站[7]来定制。
/* 变化在1s过渡 */
transition: 1s;
/* 指定过渡属性 */
transition: 1s height;
/* 指定多个属性同时发生过渡 */
transition: 1s height, 1s width;
/* 指定delay延时时间 */
transition: 1s height, 1s 1s width;
/* 指定状态变化速度 */
transition: 1s height ease;
/* 指定自定义移状态变化速度 */
transition: 1s height cubic-bezier(.83,.97,.05,1.44);
transition的局限 transition的优点在于简单易用,但是它有几个很大的局限。
-
transition需要事件触发,所以没法在网页加载时自动发生。
-
transition是一次性的,不能重复发生,除非一再触发。
-
transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。
-
一条transition规则,只能定义一个属性的变化,不能涉及多个属性。
CSS Animation就是为了解决这些问题而提出的。
-
Transition 强调过渡,Transition + Transform = 两个关键帧的Animation
-
Animation 强调流程与控制,Duration + TransformLib + Control = 多个关键帧的Animation
2. animation动画
.element:hover {
animation: 1s rainbow;
/*
animation: 1s rainbow infinite; 关键字infinite让动画无限次播放
animation: 1s rainbow 3; 指定动画播放次数
*/
}
@keyframes rainbow {
0% { background: #c00; }
50% { background: orange; }
100% { background: yellowgreen; }
}
其中animation的值是简写,扩展开依次是:
-
animation-name: 指定一个 @keyframes 的名称,动画将要使用这个@keyframes定义。
-
animation-duration: 整个动画需要的时长。
-
animation-timing-function: 动画进行中的时速控制,比如 ease 或 linear.
-
animation-delay: 动画延迟时间。
-
animation-direction: 动画重复执行时运动的方向。
-
animation-iteration-count: 动画循环执行的次数。
-
animation-fill-mode: 设置动画执行完成后/开始执行前的状态,比如,你可以让动画执行完成后停留在最后一幕,或恢复到初始状态。
-
animation-play-state: 暂停/启动动画。
- 参考:CSS动画简介[8]
10. CSS优化、提高性能的方法有哪些
-
多个css合并,尽量减少HTTP请求
-
将css文件放在页面最上面
-
移除空的css规则
-
避免使用CSS表达式
-
选择器优化嵌套,尽量避免层级过深
-
充分利用css继承属性,减少代码量
-
抽象提取公共样式,减少代码量
-
属性值为0时,不加单位
-
属性值为小于1的小数时,省略小数点前面的0
-
css雪碧图
四、javascript
- 参考:javascript面试题整理[9]
五、vue
- 参考:vue面试题整理[10]
六、webpack
-
webpack
是一个模块打包工具,你可以使用webpack管理你的模块依赖,并编绎输出模块们所需的静态文件。 -
它能够很好地管理、打包Web开发中所用到的HTML、Javascript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。
-
对于不同类型的资源,webpack有对应的模块加载器
loader
。 -
webpack模块打包器会分析模块间的依赖关系,最后生成优化且合并后的静态资源。
-
其插件功能提供了处理各种文件过程中的各个生命周期钩子,使开发者能够利用插件功能开发很多自定义的功能。
1. 我写过的webpack相关的文章
-
webpack打包原理\&手写webpack核心打包过程[11]
-
在webpack-dev-server中添加mock中间件实现前端模拟数据功能[12]
-
webpack常用配置详解[13]
-
webpack配置优化[14]
2. 核心打包原理简述
3. Loader
编写一个loader:
loader
就是一个node
模块,它输出了一个函数。当某种资源需要用这个loader
转换时,这个函数会被调用。并且,这个函数可以通过提供给它的this
上下文访问Loader API
。 reverse-txt-loader
。
解析顺序:从下向上,从右向左
// 定义
module.exports = function(src) {
//src是原文件内容(abcde),下面对内容进行处理,这里是反转
var result = src.split(‘’).reverse().join(‘’);
//返回JavaScript源码,必须是String或者Buffer
return module.exports = '${result}'
;
}
//使用
{
test: /.txt$/,
loader: ‘reverse-txt-loader’
}
4. 配置举例
§ base
module.exports = {
entry: {
app: ‘./src/main.js’
},
output: {
path: path.resolve(__dirname, ‘…/dist’),
filename: ‘[name].js’,
publicPath: ‘’
},
resolve: {
extensions: [‘.js’, ‘.vue’, ‘.json’, ‘.css’, ‘.less’],
alias: {
‘@’: resolve(‘src’),
src: resolve(‘src’),
static: resolve(‘static’)
}
},
module: {
rules: [
{
test: /.vue$/,
loader: ‘vue-loader’,
options: vueLoaderConfig
},
{
test: /.js$/,
loader: ‘babel-loader’,
include: [resolve(‘src’), resolve(‘test’)]
},
{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
loader: ‘url-loader’,
query: {
limit: 1,
name: utils.assetsPath(img/[name].[ext]
)
},
include: /nobase64/
},
{
test: /.svg(?\S*)?$/,
loader: ‘svg-sprite-loader’,
query: {
prefixize: true,
name: ‘[name]-[hash]’
},
include: [resolve(‘src’)],
exclude: /node_modules|bower_components/
}
]
},
plugins: [
new VueLoaderPlugin(),
new ProgressBarPlugin({
format: ‘build [:bar] ’ + chalk.green.bold(’:percent’) + ’ (:elapsed seconds) : (:msg)',
clear: false,
width: 60
})
]
};
§ dev
var path = require(‘path’);
var utils = require(‘./utils’);
var webpack = require(‘webpack’);
var config = require(‘…/config’);
var merge = require(‘webpack-merge’);
var baseWebpackConfig = require(‘./webpack.base.conf’);
var CopyWebpackPlugin = require(‘copy-webpack-plugin’);
var MyPlugin = require(‘./htmlPlugin’);
var HtmlWebpackPlugin = require(‘html-webpack-plugin’);
var MiniCssExtractPlugin = require(‘mini-css-extract-plugin’);
var OptimizeCSSPlugin = require(‘optimize-css-assets-webpack-plugin’);
const TerserPlugin = require(‘terser-webpack-plugin’);
module.exports = merge(baseWebpackConfig, {
mode: ‘development’,
externals: {
vue: ‘Vue’
},
devtool: ‘#source-map’,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath(js/[name].js
),
chunkFilename: utils.assetsPath(js/[name].js
)
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new FriendlyErrorsPlugin(),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, ../static
),
to: path.resolve(config.dev.assetsPublicPath, /dist/static
)
}
]),
new HtmlWebpackPlugin({
alwaysWriteToDisk: true,
filename: ‘index.html’,
template: path.resolve(__dirname, ../src/index.html
), // 模板路径
inject: false,
excludeChunks: [],
baseUrl: ‘’,
currentEnv: ‘development’,
envName: ‘local’,
curentBranch: ‘’
}),
new HtmlHardDisk()
],
optimization: {
/*
作用域提升插件
[注意] 这个插件在 mode: production 时时默认开启的
这样配置时为了在 development 时也开启
https://webpack.js.org/configuration/optimization/#optimizationconcatenatemodules
*/
concatenateModules: true,
splitChunks: {
cacheGroups: {
commons: {
test: /[\/]node_modules[\/]/,
name: ‘vendors’,
chunks: ‘all’
},
styles: {
name: ‘styles’,
test: /.css$/,
chunks: ‘all’,
enforce: true
}
}
},
runtimeChunk: {
name: ‘manifest’
},
minimizer: [
// 代码压缩UglifyJsPlugin的升级版
new TerserPlugin({
cache: true,
parallel: true,
terserOptions: {
sourceMap: true,
warnings: false,
compress: {
// warnings: false
},
ecma: 6,
mangle: true
},
sourceMap: true
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
autoprefixer: {
browsers: ‘last 2 version, IE > 8’
}
}
})
]
}
}
§ prod
var path = require(‘path’);
var utils = require(‘./utils’);
var webpack = require(‘webpack’);
var merge = require(‘webpack-merge’);
var baseWebpackConfig = require(‘./webpack.base.conf’);
var HtmlWebpackPlugin = require(‘html-webpack-plugin’);
var FriendlyErrorsPlugin = require(‘friendly-errors-webpack-plugin’);
var CopyWebpackPlugin = require(‘copy-webpack-plugin’);
var HtmlHardDisk = require(‘html-webpack-harddisk-plugin’);
var MiniCssExtractPlugin = require(‘mini-css-extract-plugin’);
var OptimizeCSSPlugin = require(‘optimize-css-assets-webpack-plugin’);
const TerserPlugin = require(‘terser-webpack-plugin’);
module.exports = merge(baseWebpackConfig, {
mode: ‘production’,
externals: {
vue: ‘Vue’
},
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath(js/[name].js
),
chunkFilename: utils.assetsPath(js/[name]-[chunkhash].js
)
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
‘process.env’: env
}),
// extract css into its own file
new MiniCssExtractPlugin({
filename: utils.assetsPath(‘css/[name].css’),
allChunks: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, ../static
),
to: path.resolve(__dirname, ../dist/static
)
}
]),
new HtmlWebpackPlugin({
alwaysWriteToDisk: true,
filename: ‘index.html’,
template: path.resolve(__dirname, ../src/index.html
), // 模板路径
inject: false,
baseUrl: ‘’,
currentEnv: ‘production’,
envName: ‘prod’,
curentBranch: ‘’
}),
new BundleAnalyzerPlugin()
],
optimization: {
minimizer: [
// 代码压缩UglifyJsPlugin的升级版
new TerserPlugin({
// cache: true,
parallel: true,
terserOptions: {
warnings: false,
compress: {
},
// ecma: 6,
mangle: true
},
sourceMap: true
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
autoprefixer: {
browsers: ‘last 2 version, IE > 8’
}
}
})
],
splitChunks: {
cacheGroups: {
commons: {
test: /[\/]node_modules[\/]/,
name: ‘vendors’,
chunks: ‘all’
}
}
},
runtimeChunk: {
name: ‘manifest’
}
}
};
5. 手动chungk分包
-
optimization.splitChunks(4之前老版本用CommonsChunkPlugin)
-
vue路由懒加载[15]
6. 打包加速的方法
-
devtool 的 sourceMap较为耗时
-
开发环境不做无意义的操作:代码压缩、目录内容清理、计算文件hash、提取CSS文件等
-
第三方依赖外链script引入:vue、ui组件、JQuery等
-
HotModuleReplacementPlugin:热更新增量构建
-
DllPlugin& DllReferencePlugin:动态链接库,提高打包效率,仅打包一次第三方模块,每次构建只重新打包业务代码。
-
thread-loader,happypack:多线程编译,加快编译速度
-
noParse:不需要解析某些模块的依赖
-
babel-loader开启缓存cache
-
splitChunks(老版本用CommonsChunkPlugin):提取公共模块,将符合引用次数(minChunks)的模块打包到一起,利用浏览器缓存
-
Tree Shaking 摇树:基于ES6提供的模块系统对代码进行静态分析, 并在压缩阶段将代码中的死代码(dead code)移除,减少代码体积。
7. 打包体积 优化思路
-
webpack-bundle-analyzer插件可以可视化的查看webpack打包出来的各个文件体积大小,以便我们定位大文件,进行体积优化
-
提取第三方库或通过引用外部文件的方式引入第三方库
-
代码压缩插件
UglifyJsPlugin
-
服务器启用gzip压缩
-
按需加载资源文件
require.ensure
= -
剥离
css
文件,单独打包 -
去除不必要插件,开发环境与生产环境用不同配置文件
-
SpritesmithPlugin雪碧图,将多个小图片打包成一张,用background-image,backgroud-pisition,width,height控制显示部分
-
url-loader 文件大小小于设置的尺寸变成base-64编码文本,大与尺寸由file-loader拷贝到目标目录
8. Tree Shaking 摇树
背景: 项目中,有一个入口文件,相当于一棵树的主干,入口文件有很多依赖的模块,相当于树枝。实际情况中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过 tree-shaking,将没有使用的模块摇掉,这样来达到删除无用代码的目的。
思路: 基于ES6提供的模块系统对代码进行静态分析,并将代码中的死代码(dead code)移除的一种技术。因此,利用Tree Shaking技术可以很方便地实现我们代码上的优化,减少代码体积。
Tree Shaking 摇树 是借鉴了 rollup 的实现。
摇树删除代码的原理: webpack基于ES6提供的模块系统,对代码的依赖树进行静态分析,把import & export标记为3类:
-
所有import标记为/* harmony import */
-
被使用过的export标记为/harmony export([type])/,其中[type]和webpack内部有关,可能是binding,immutable等;
-
没有被使用的export标记为/* unused harmony export [FuncName] */,其中[FuncName]为export的方法名,之后使用Uglifyjs(或者其他类似的工具)进行代码精简,把没用的都删除。
为何基于es6模块实现(ES6 module 特点:):
-
只能作为模块顶层的语句出现
-
import的模块名只能是字符串常量
-
import binding是immutable的
条件:
-
首先源码必须遵循 ES6 的模块规范 (import & export),如果是 CommonJS 规范 (require) 则无法使用。
-
编写的模块代码不能有副作用,如果在代码内部改变了外部的变量则不会被移除。
配置方法:
在package.json里添加一个属性:
{
// sideEffects如果设为false,webpack就会认为所有没用到的函数都是没副作用的,即删了也没关系。
“sideEffects”: false,
// 设置黑名单,用于防止误删代码
“sideEffects”: [
// 数组里列出黑名单,禁止shaking下列代码
“@babel/polly-fill”,
“*.less”,
// 其它有副作用的模块
“./src/some-side-effectful-file.js”
],
}
tree-shaking 摇掉代码中未使用的代码 在生产模式下自动开启
tree-shaking并不是webpack中的某一个配置选项,是一组功能搭配使用后的优化效果,会在生产模式下自动启动
// 在开发模式下,设置 usedExports: true ,打包时只会标记出哪些模块没有被使用,不会删除,因为可能会影响 source-map的标记位置的准确性。
{
mode: ‘develpoment’,
optimization: {
// 优化导出的模块
usedExports: true
},
}
// 在生产模式下默认开启 usedExports: true ,打包压缩时就会将没用到的代码移除
{
mode: ‘production’,
// 这个属性的作用就是集中配置webpack内部的优化功能
optimizition: {
// 只导出外部使用的模块成员 负责标记枯树叶
usedExports: true,
minimize: true, // 自动压缩代码 负责摇掉枯树叶
/**
* webpack打包默认会将一个模块单独打包到一个闭包中
* webpack3中新增的API 将所有模块都放在一个函数中 ,尽可能将所有模块合并在一起,
* 提升效率,减少体积 达到作用域提升的效果
*/
concatenateModules: true,
},
}
使用摇树的注意事项:
-
使用 ES6 模块语法编写代码
-
工具类函数尽量以单独的形式输出,不要集中成一个对象或者类
-
声明 sideEffects
-
自己在重构代码时也要注意副作用
tree-shaking & babel 使用babel-loader处理js代码会导致tree-shaking失效的原因:
- treeshaking 使用的前提必须是ES module组织的代码,也就是说交给ESMOdule处理的代码必须是ESM。当我们使用babel-loader处理js代码之后就有可能将ESM 转换 成commonjs规范(preset-env插件工作的时候就会将esm => coommonjs)
解决办法:
收到配置preset-env的modules:false,确保不会开启自动转换的插件(在最新版本的babel-loader中自动帮我们关闭了转换成commonjs规范的功能)
presets: [
[‘@babel/preset-env’, {module: ‘commonjs’}]
]
9. 常用插件简述
-
webpack-dev-server
-
clean-webpack-plugin:编译前清理输出目录
-
CopyWebpackPlugin:复制文件
-
HotModuleReplacementPlugin:热更新
-
ProvidePlugin:全局变量设置
-
DefinePlugin:定义全局常量
-
splitChunks(老版本用CommonsChunkPlugin):提取公共模块,将符合引用次数的模块打包到一起
-
mini-css-extract-plugin(老版本用ExtractTextWebpackPlugin):css单独打包
-
TerserPlugin(老版本用UglifyJsPlugin):压缩代码
-
progress-bar-webpack-plugin:编译进度条
-
DllPlugin& DllReferencePlugin:提高打包效率,仅打包一次第三方模块
-
webpack-bundle-analyzer:可视化的查看webpack打包出来的各个文件体积大小
-
thread-loader,happypack:多进程编译,加快编译速度
nodejs
1. 我写的nodejs相关文章
-
koa+mongondb实现用户登录注册模块[16]
-
nodejs的fs模块回调函数风格的异步操作转化为promise和await风格[17]
2. nodejs常用模块
-
path
-
fs
-
http,url
-
express
-
koa
-
mongoose
-
process
-
cookie, session
-
crypto加密相关
-
os
3. koa 中间件思想,洋葱模型
class Middleware {
constructor() {
this.middlewares = [];
}
use(fn) {
if(typeof fn !== ‘function’) {
throw new Error('Middleware must be function, but get ’ + typeof fn);
}
this.middlewares.push(fn);
return this;
}
compose() {
const middlewares = this.middlewares;
return dispatch(0);
function dispatch(index) {
const middleware = middlewares[index];
if (!middleware) {return;}
try{
const ctx = {};
const result = middleware(ctx, dispatch.bind(null, index + 1));
return Promise.resolve(result);
} catch(err) {
return Promise.reject(err);
}
}
}
}
// 使用
const middleware = new Middleware();
middleware.use(async (ctx, next) => {
console.log(1);
await next();
console.log(2);
});
middleware.use(async (ctx, next) => {
console.log(3);
await next();
console.log(4);
});
middleware.compose();// 1 3 4 2
4. express和koa的区别
-
编码风格:express采用回调函数风格,koa1 采用 generator,koa2(默认)使用await,风格上更加优雅,koa与es6,7的结合更加紧密;
-
错误处理:express采用在回调中错误优先的处理方式,深层次的异常捕获不了,使得必须在每一层回调里面处理错误,koa的使用try catch捕获错误,将错误上传可以统一处理错误;
-
Koa 把 Express 中内置的 router、view 等功能都移除了,使得框架本身更轻量;
-
express社区较大,文档也相对较多,koa社区相对较小;
网络
–
1. 网络七层协议(OSI模型)
OSI是一个定义良好的协议规范集,并有许多可选部分完成类似的任务。它定义了开放系统的层次结构、层次之间的相互关系以及各层所包括的可能的任务,作为一个框架来协调和组织各层所提供的服务。
OSI参考模型并没有提供一个可以实现的方法,而是描述了一些概念,用来协调进程间通信标准的制定。即OSI参考模型并不是一个标准,而是一个在制定标准时所使用的概念性框架。
image.png
- 第7层 应用层
应用层(Application Layer)提供为应用软件而设计的接口,以设置与另一应用软件之间的通信。例如:HTTP、HTTPS、FTP、Telnet、SSH、SMTP、POP3等。
- 第6层 表示层
表示层(Presentation Layer)把数据转换为能与接收者的系统格式兼容并适合传输的格式。
- 第5层 会话层
会话层(Session Layer)负责在数据传输中设置和维护计算机网络中两台计算机之间的通信连接。
- 第4层 传输层
传输层(Transport Layer)把传输表头(TH)加至数据以形成数据包。传输表头包含了所使用的协议等发送信息。例如:传输控制协议(TCP)等。
- 第3层 网络层
网络层(Network Layer)决定数据的路径选择和转寄,将网络表头(NH)加至数据包,以形成分组。网络表头包含了网络资料。例如:互联网协议(IP)等。
- 第2层 数据链路层
数据链路层(Data Link Layer)负责网络寻址、错误侦测和改错。当表头和表尾被加至数据包时,会形成信息框(Data Frame)。数据链表头(DLH)是包含了物理地址和错误侦测及改错的方法。数据链表尾(DLT)是一串指示数据包末端的字符串。例如以太网、无线局域网(Wi-Fi)和通用分组无线服务(GPRS)等。
分为两个子层:逻辑链路控制(logical link control,LLC)子层和介质访问控制(Media access control,MAC)子层。
- 第1层 物理层
物理层(Physical Layer)在局部局域网上发送数据帧(Data Frame),它负责管理电脑通信设备和网络媒体之间的互通。包括了针脚、电压、线缆规范、集线器、中继器、网卡、主机接口卡等。
2. TCP 协议三次握手
-
客户端通过
SYN
报文段发送连接请求,确定服务端是否开启端口准备连接。状态设置为SYN_SEND
; -
服务器如果有开着的端口并且决定接受连接,就会返回一个
SYN+ACK
报文段给客户端,状态设置为SYN_RECV
; -
客户端收到服务器的
SYN+ACK
报文段,向服务器发送ACK
报文段表示确认。此时客户端和服务器都设置为ESTABLISHED
状态。连接建立,可以开始数据传输了。
翻译成大白话就是: 客户端:你能接收到我的消息吗? 服务端:可以的,那你能接收到我的回复吗? 客户端:可以,那我们开始聊正事吧。
为什么是3次?:避免历史连接,确认客户端发来的请求是这次通信的人 为什么不是4次?:3次够了第四次浪费
3. TCP 协议四次挥手
image.png
- 为什么不是两次?
- 两次情况客户端说完结束就立马断开不再接收,无法确认服务端是否接收到断开消息,但且服务端可能还有消息未发送完。
为什么不是三次?
- 3次情况服务端接收到断开消息,向客户端发送确认接受消息,客户端未给最后确认断开的回复。
TCP协议
- TCP 和 UDP 的区别?
- TCP 三次握手的过程?
- 为什么是三次而不是两次、四次?
- 三次握手过程中可以携带数据么?
- 说说 TCP 四次挥手的过程
- 为什么是四次挥手而不是三次?
- 半连接队列和 SYN Flood 攻击的关系
- 如何应对 SYN Flood 攻击?
- 介绍一下 TCP 报文头部的字段
- TCP 快速打开的原理(TFO)
- 说说TCP报文中时间戳的作用?
- TCP 的超时重传时间是如何计算的?
- TCP 的流量控制
- TCP 的拥塞控制
- 说说 Nagle 算法和延迟确认?
- 如何理解 TCP 的 keep-alive?
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
浏览器篇
- 浏览器缓存?
- 说一说浏览器的本地存储?各自优劣如何?
- 说一说从输入URL到页面呈现发生了什么?
- 谈谈你对重绘和回流的理解
- XSS攻击
- CSRF攻击
- HTTPS为什么让数据传输更安全?
- 实现事件的防抖和节流?
- 实现图片懒加载?
1. 网络七层协议(OSI模型)
OSI是一个定义良好的协议规范集,并有许多可选部分完成类似的任务。它定义了开放系统的层次结构、层次之间的相互关系以及各层所包括的可能的任务,作为一个框架来协调和组织各层所提供的服务。
OSI参考模型并没有提供一个可以实现的方法,而是描述了一些概念,用来协调进程间通信标准的制定。即OSI参考模型并不是一个标准,而是一个在制定标准时所使用的概念性框架。
image.png
- 第7层 应用层
应用层(Application Layer)提供为应用软件而设计的接口,以设置与另一应用软件之间的通信。例如:HTTP、HTTPS、FTP、Telnet、SSH、SMTP、POP3等。
- 第6层 表示层
表示层(Presentation Layer)把数据转换为能与接收者的系统格式兼容并适合传输的格式。
- 第5层 会话层
会话层(Session Layer)负责在数据传输中设置和维护计算机网络中两台计算机之间的通信连接。
- 第4层 传输层
传输层(Transport Layer)把传输表头(TH)加至数据以形成数据包。传输表头包含了所使用的协议等发送信息。例如:传输控制协议(TCP)等。
- 第3层 网络层
网络层(Network Layer)决定数据的路径选择和转寄,将网络表头(NH)加至数据包,以形成分组。网络表头包含了网络资料。例如:互联网协议(IP)等。
- 第2层 数据链路层
数据链路层(Data Link Layer)负责网络寻址、错误侦测和改错。当表头和表尾被加至数据包时,会形成信息框(Data Frame)。数据链表头(DLH)是包含了物理地址和错误侦测及改错的方法。数据链表尾(DLT)是一串指示数据包末端的字符串。例如以太网、无线局域网(Wi-Fi)和通用分组无线服务(GPRS)等。
分为两个子层:逻辑链路控制(logical link control,LLC)子层和介质访问控制(Media access control,MAC)子层。
- 第1层 物理层
物理层(Physical Layer)在局部局域网上发送数据帧(Data Frame),它负责管理电脑通信设备和网络媒体之间的互通。包括了针脚、电压、线缆规范、集线器、中继器、网卡、主机接口卡等。
2. TCP 协议三次握手
-
客户端通过
SYN
报文段发送连接请求,确定服务端是否开启端口准备连接。状态设置为SYN_SEND
; -
服务器如果有开着的端口并且决定接受连接,就会返回一个
SYN+ACK
报文段给客户端,状态设置为SYN_RECV
; -
客户端收到服务器的
SYN+ACK
报文段,向服务器发送ACK
报文段表示确认。此时客户端和服务器都设置为ESTABLISHED
状态。连接建立,可以开始数据传输了。
翻译成大白话就是: 客户端:你能接收到我的消息吗? 服务端:可以的,那你能接收到我的回复吗? 客户端:可以,那我们开始聊正事吧。
为什么是3次?:避免历史连接,确认客户端发来的请求是这次通信的人 为什么不是4次?:3次够了第四次浪费
3. TCP 协议四次挥手
image.png
- 为什么不是两次?
- 两次情况客户端说完结束就立马断开不再接收,无法确认服务端是否接收到断开消息,但且服务端可能还有消息未发送完。
为什么不是三次?
- 3次情况服务端接收到断开消息,向客户端发送确认接受消息,客户端未给最后确认断开的回复。
TCP协议
- TCP 和 UDP 的区别?
- TCP 三次握手的过程?
- 为什么是三次而不是两次、四次?
- 三次握手过程中可以携带数据么?
- 说说 TCP 四次挥手的过程
- 为什么是四次挥手而不是三次?
- 半连接队列和 SYN Flood 攻击的关系
- 如何应对 SYN Flood 攻击?
- 介绍一下 TCP 报文头部的字段
- TCP 快速打开的原理(TFO)
- 说说TCP报文中时间戳的作用?
- TCP 的超时重传时间是如何计算的?
- TCP 的流量控制
- TCP 的拥塞控制
- 说说 Nagle 算法和延迟确认?
- 如何理解 TCP 的 keep-alive?
[外链图片转存中…(img-oHSIfHk3-1715262520844)]
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
浏览器篇
- 浏览器缓存?
- 说一说浏览器的本地存储?各自优劣如何?
- 说一说从输入URL到页面呈现发生了什么?
- 谈谈你对重绘和回流的理解
- XSS攻击
- CSRF攻击
- HTTPS为什么让数据传输更安全?
- 实现事件的防抖和节流?
- 实现图片懒加载?
[外链图片转存中…(img-hliiVIob-1715262520845)]