目录
开发环境
一、webpack、vite、babel
二、git
常用命令
git add .
git branch
git checkout XX
git checkcout -b XX
git commit -m "XX"
git push origin master
git pull origin master
git merge XX
几个命令的区别
git fetch / git pull : pull = fetch + merge
git reset / git revert:reset硬性回滚,回滚到过去某个点,目标版本后面的提交记录全部消失;revert 安全,添加新的提交来修复错误
git merge / git rebase:rebase提交记录是线性
三、Chrome调试工具
Elements Console debugger Network Application
四、抓包
移动端H5查看网络请求,需要用工具抓包。
Windows一般用fiddler,Mac OS一般用charles
五、linux常用命令
运行环境
一、网页加载过程
1、浏览器从输入URL到页面渲染的整个流程
1)加载资源
加载资源的形式:
html代码;媒体文件,如图片、视频等;javascript css
加载资源的过程:
a)URL解析:浏览器解析输入的URL,确定协议、主机名、端口号和路径
b)DNS查询:浏览器会依据URL逐层查询DNS服务器缓存,解析URL中的域名对应的IP地址,DNS缓存从近到远依次是浏览器缓存、系统缓存、路由器缓存、IPS服务器缓存、域名服务器缓存、顶级域名服务器缓存。从哪个缓存找到对应的IP直接返回,不再查询后面的缓存。
c)TCP连接:结合三次握手
d)发送HTTP请求:浏览器发出读取文件的HTTP请求,该请求发送给服务器
e)服务器处理请求并返回HTTP报文:服务器对浏览器请求做出响应,把对应的带有HTML文本的HTTP响应报文发送给浏览器
f)浏览器解析渲染页面
g)连接结束:浏览器释放TCP连接,该步骤即四次挥手。第5步和第6步可以认为是同时发生的,哪一步在前没有特别的要求
2)页面渲染
参见下面的浏览器渲染机制
2、浏览器渲染机制
- 解析HTML生成DOM树
- 解析CSS生成CSSOM树(CSS规则树)
- 将DOM树与CSSOM树合并在一起生成Render Tree渲染树
- 布局。计算每个元素在视口中的确切位置和大小。首次布局称为"布局",后续布局称为"回流"或"重排"
- 绘制。将布局计算的几何信息转换为屏幕上的实际像素,包括文本、颜色、边框、阴影等视觉部分的绘制。通常分为多个层(layers)进行绘制
- 合成与显示。浏览器将各层合并(Composite)后显示在屏幕上,利用GPU加速处理某些层的合成
当HTML解析器遇到<script>
标签时:
- 暂停HTML文档解析
- 下载并执行JavaScript代码(除非有async/defer属性)
- 执行完成后继续解析HTML
window.onload和DOMContentLoaded区别
window.onload:页面的全部资源加载完才会执行,包括图片、视频等
DOMContentLoaded:DOM渲染完即可执行,此时图片、视频还可能没有加载完
3、重排/回流、重绘
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color,称为重绘(repaint)。
常见的引起重绘(repaint)属性和方法:
当render tree中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建,称为回流(reflow)。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树。完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。
常见的引起回流(reflow)属性和方法:
回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流
当页面布局和几何属性改变时就需要回流。比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变
4、async和defer区别
在 HTML 中加载外部 JavaScript 脚本时,defer
和 async
是两个常用的脚本加载属性,它们都能实现脚本的异步加载
适用async的场景
<!-- 不依赖 DOM 的第三方库 -->
<script async src="https://cdn.example.com/library.js"></script>
const script = document.createElement('script');
script.src = 'script.js';
document.body.appendChild(script); // 动态加载脚本默认 async 行为
适用defer的场景
<!-- 主应用脚本(需要操作 DOM) -->
<script defer src="app.js"></script>
<!-- 依赖其他脚本的库 -->
<script defer src="library.js"></script>
<script defer src="dependent-script.js"></script> <!-- 保证在 library.js 后执行 -->
<script type="module" src="main.js"></script> // 模块化脚本默认具有 defer 行为(可以加上 async 改变行为)
二、性能优化
1、性能优化原则
多使用内存、缓存或其他方法
减少CPU计算量,减少网络加载耗时
(以空间换时间)
2、性能优化方法
1)加载更快
减少资源体积:压缩代码
减少访问次数:合并代码、SSR服务端渲染、缓存
使用更快的网络:CDN(根据区域做服务器处理)
2)渲染更快
CSS放在head,JS放在body最下面
尽早开始执行JS,用DOMContentLoaded触发
懒加载(图片懒加载,上滑加载更多)
对DOM查询进行缓存
频繁DOM操作,合并到一起插入DOM结构
节流throttle 防抖debounce
注:
SSR 服务器端渲染:将网页和数据一起加载,一起渲染
非SSR(前后端分离):先加载网页,再加载数据,再渲染数据
JavaScript如何实现图片懒加载(lazyload) 提高用户体验、js实现图片懒加载原理
3、首屏渲染优化
页面渲染性能指标
1) 关键渲染指标:
LCP最大内容绘制,测量加载性能,≤2.5秒
CLS累计布局偏移,测量视觉稳定性,≤0.1
2) 关键时间节点指标:
FP首次绘制 - 第一个像素出现
FCP首次内容绘制 - 第一个文本/图像内容出现
TTI可交互时间 - 页面完全可响应的时间
3)其他几个重要指标
TTFB 浏览器发送请求后接收到第一个字节的时间
INP 用户交互(点击、输入)到页面视觉反馈的时间
FP → FCP → LCP → DCL(DOM Content Loaded) → Load → TTI ↑ 布局稳定性(CLS)
首屏渲染优化核心手段
1)减少关键资源体积
- 压缩HTML、CSS、JavaScript文件
- 使用Tree-shaking移除未使用代码
- 代码分割(Code Splitting)按需加载
2)优化关键渲染路径
- 内联关键CSS(Critical CSS)
- 延迟非关键CSS加载
- 异步加载JavaScript(使用async/defer)
3)资源预加载
- 使用
<link rel="preload">
预加载关键资源 - DNS预解析
<link rel="dns-prefetch">
- 预连接
<link rel="preconnect">
4、防抖和节流
防抖:用户动作暂停或结束,触发请求。
- 持续触发不执行
- 不触发的一段时间之后再执行
应用场景:
- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
HTML:
<input id="input1">
<script src="js/debounce.js"></script>
js:
const input1=document.getElementById('input1')
function debounce(fn,delay=500){
//timer是闭包中的
let timer=null
return function(){
if(timer){
clearTimeout(timer)
}
timer=setTimeout(()=>{
fn.apply(this,arguments)
timer=null
},delay)
}
}
input1.addEventListener('keyup',debounce(function (){
console.log(input1.value)
},500))
节流
- 持续触发并不会执行多次
- 到一定时间再去执行
应用场景:
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
HTML:
<div id="div1" draggable="true">可拖拽</div>
<script src="js/throttle.js"></script>
CSS:
#div1{
border:1px solid #ccc;
width:200px;
height:200px;
}
js:
const div1=document.getElementById('div1')
function throttle(fn,delay=100){
let timer=null
return function(){
if(timer){
return
}
timer=setTimeout(()=>{
fn.apply(this,arguments)
timer=null
},delay)
}
}
div1.addEventListener('drag',throttle(function(e){
console.log(e.offsetX,e.offsetY)
},200))
手写防抖/节流
// 防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次触发,则重新计算时间
function debounce(func, time) {
let timeout=null;
return function () {
clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(this, arguments)
}, time);
}
}
// 节流:高频事件触发,n秒内只会执行一次
// 时间戳版本
function throttle(func, delay) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
// 如果距离上次执行时间大于delay则执行
if (now - lastTime >= delay) {
func.apply(this, args);
lastTime = now;
}
};
}
// 定时器版本
function throttle(func, delay) {
let timer = null;
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
}
};
}
三、安全
常见的web前端攻击方式
1、XSS跨站脚本攻击
攻击者在web页面插入恶意的代码。当用户浏览该页面的时候,代码执行,从而实现攻击目的。
防御:
输入过滤,对用户提交的数据进行有效性验证,仅接受指定长度范围内并符合我们期望格式的的内容提交,阻止或者忽略除此外的其他任何数据。
输出编码,把变量输出到页面时要做好相关的编码转义工作,如要输出到 <script>中,可以进行JS编码;要输出到HTML内容或属性,则进行HTML编码处理。根据不同的语境采用不同的编码处理方式。
HttpOnly Cookie,将重要的cookie标记为http only, 这样的话当浏览器向Web服务器发起请求时就会带上cookie字段,但是在脚本中却不能访问这个cookie,这样就避免了XSS攻击利用JavaScript的document.cookie获取cookie
2、CSRF/XSRF跨站请求伪造攻击
攻击者盗用你的身份,以你的名义向第三方网站发送恶意请求。比如盗取你的账号,以你的身份发送邮件,购买商品等。
防御:
使用post接口
增加验证,例如指纹、支付密码
将cookie设置为HttpOnly
参考:XSS跨站脚本攻击与CSRF跨站请求伪造攻击的学习总结
3、sql注入攻击
SQL注入是一种通过操作输入来修改后台SQL语句进行攻击的技术。
防御:
输入过滤
场景题
思路:交代背景、调研方案、方案落地、反思追求更有解
1、出现白屏怎么排查原因?
1)控制台检查
打开浏览器开发者工具(F12),查看Console面板是否有报错(红色错误),注意警告(黄色提示)也可能导致问题
2)网络请求分析
切换到Network面板,检查关键资源(HTML、JS、CSS)是否加载成功,查看失败的请求(状态码4xx/5xx)
3)DOM结构验证
在Elements面板检查DOM是否正常渲染,查看<body>
内是否有内容
2、前端埋点SDK设计思路?
数据流设计:采集 -> 处理 -> 缓存 -> 上报 -> 确认
设计原则:
1)无侵入性
对业务代码影响最小化;自动收集通用数据(页面访问、性能指标等)
2)高性能
异步上报机制;数据批量压缩上传;不影响主线程性能
3)可扩展性
支持多种埋点类型;插件化架构设计;自定义上报策略
4、页面请求接口大规模并发?100个请求,如何使用promise控制并发?
5、使用params实现每隔1s输出1、2、3
6、一次发任意多个请求,如果失败则重发,直到所有的都成功,或者超出最大重试次数,才返回最终结果
5、H5移动端适配问题如何解决?
1)视口基础配置
HTML meta 标签设置
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no, shrink-to-fit=no" />
- width=device-width :设置视口宽度等于设备的屏幕宽度
- initial-scale=1.0 :设置初始缩放比例为1.0(不缩放)
- maximum-scale=1 :限制用户最大缩放比例为1(禁止放大)
- user-scalable=no :禁止用户手动缩放页面
- shrink-to-fit=no :防止某些浏览器(如iOS Safari)自动缩小内容以适应屏幕
2)媒体查询适配
/* 小型设备 (手机) */
@media (max-width: 576px) {
.container {
padding: 0 10px;
}
}
/* 中型设备 (平板) */
@media (min-width: 577px) and (max-width: 768px) {
.container {
padding: 0 20px;
}
}
/* 大型设备 (桌面) */
@media (min-width: 769px) {
.container {
max-width: 1200px;
margin: 0 auto;
}
}
3)动态单位适配方案
rem 适配方案、vm/vh
6、monorepo优缺点?管理工具?npm、yarn、pnpm区别?
优点:
-
代码共享便捷:所有项目/包在同一仓库,方便共享代码和工具
-
统一工作流:一致的构建、测试和发布流程
-
原子提交:跨多个包的修改可以一次提交,保持一致性
缺点:
-
规模膨胀:仓库体积会随时间快速增长
-
构建工具复杂:需要更复杂的工具链支持
-
权限控制困难:难以精细控制不同团队的访问权限
npm
-
Node.js 原生捆绑
-
最大的生态兼容性
-
无需额外安装
pnpm
严格版本控制 + 共享存储
yarn
确定性锁文件 (yarn.lock)