(直接背,面试张口就来)
一、核心问题:为什么 POST 经常发两次?
-
这不是两次 POST,而是浏览器的预检请求(OPTIONS)。
-
当请求是非简单请求时,浏览器会先发送一次 OPTIONS 请求,向服务器询问:“我能不能跨域请求你?”
-
服务器返回允许后,才会发送真正的 POST 请求;如果服务器拒绝,就会直接报跨域错误。
-
GET 请求大多是 “简单请求”,所以很少触发预检。
这不是两次 POST,而是浏览器的预检请求(OPTIONS)。
当请求是非简单请求时,浏览器会先发送一次 OPTIONS 请求,向服务器询问:“我能不能跨域请求你?”
服务器返回允许后,才会发送真正的 POST 请求;如果服务器拒绝,就会直接报跨域错误。
GET 请求大多是 “简单请求”,所以很少触发预检。
表格
Pinia 是 Vuex 的升级版,也是 Vue3 官方推荐的状态管理方案;
Vuex 是旧方案,已逐步被淘汰;
Vue3 是框架底层,Pinia 基于 Vue3 构建。
写法极简:去掉了 mutation,仅保留 state / getters / actions,大幅简化代码。
完美支持 TypeScript:天然类型推断,无需额外配置。
模块化更友好:无需手动配置 modules,store 天然分模块,支持直接 import 使用。
体积更小,性能更好:比 Vuex 更轻量,热更新体验更友好。
与 Vue3 完全对齐:和 Vue3 的响应式体系、Composition API 深度融合,开发体验一致。
keep-alive 不会重复创建 / 销毁组件?keep-alive 是 Vue 内置的抽象组件,它不会渲染成真实 DOM,只负责做组件实例缓存,避免组件反复创建 / 销毁,从而提升性能。内部用 Map 对象缓存组件实例,通过组件的 key 匹配缓存。
命中缓存时,直接复用实例,跳过 created / mounted / destroyed 等常规生命周期。
创建实例:初始化 axios 实例,配置 baseURL、timeout、请求头等基础信息。
请求拦截器:请求发送前执行,统一处理 Token、请求签名、加载状态(loading)等。
发起请求:浏览器端用 XMLHttpRequest,Node.js 端用 http 模块发送 HTTP 请求。
响应拦截器:服务端返回响应后执行,处理状态码、剥取响应数据、统一错误处理。
业务层接收:拿到最终的响应数据或错误信息,进行业务逻辑处理。
✅ 优点:JS 可直接读写,封装简单,不会自动随请求携带
❌ 缺点:极易被 XSS 攻击窃取,页面注入恶意脚本后,Token 会直接被盗
🎯 适用场景:不敏感的小型项目、演示项目(非生产环境)
**HttpOnly**:禁止 JS 读取 Cookie,从根源防 XSS 攻击
**Secure**:仅在 HTTPS 协议下传输,防止明文传输被劫持
**SameSite**:限制跨站请求携带 Cookie,防止 CSRF 攻击
不是简单的函数套函数,而是函数 + 其词法环境的组合。
当内部函数被外部引用时,会带走外部函数的执行上下文,让外部函数的变量不会被垃圾回收,这是闭包的核心。
防抖 / 节流:利用闭包保存 timer 变量,每次调用都能访问上一次的计时器,实现延迟执行。
循环绑定事件:解决 var 没有块级作用域的问题,用立即执行函数(IIFE)保存每次循环的变量值。
模块化封装:私有化变量,避免全局污染,实现函数颗粒化,只暴露需要的 API。
这是前端调试的基础,也是最常用的手段。
console.log)除了 log,还有这些高效的调试方式:
当问题出在接口请求、页面卡顿或性能瓶颈时,用这一层的工具:
线上环境的问题,需要这些工具和方案:
浏览器的垃圾回收机制基于可达性分析:无法被根对象访问到的对象,会被自动回收。
内存泄漏:对象本应被回收,但因存在无效引用,导致无法被 GC 标记为 “不可达”,长期占用内存,造成页面卡顿、崩溃。
定时器 / 事件监听未销毁:组件卸载时,setInterval、addEventListener 未清除,回调函数持有组件引用。
DOM 引用未释放:DOM 元素被删除,但 JS 中仍保留对它的引用(如全局变量存储),导致无法回收。
闭包持有大对象:闭包意外引用了大对象(如 DOM、数组),导致对象无法被回收。
全局变量滥用:挂载在 window 上的变量未清理,生命周期与页面一致,长期占用内存。
第三方库实例未销毁:如图表、地图实例,组件卸载时未调用 destroy() 方法。
浏览器会对静态资源(JS/CSS/ 图片等)做强缓存:
如果文件名不变,浏览器会直接读取本地缓存,不会向服务器请求新文件,导致用户一直看到旧页面。
即使服务器更新了文件,只要 URL 没变,浏览器就会认为资源未更新,继续使用旧缓存。
强缓存:浏览器直接用本地缓存,不发请求。Hash 的作用就是破坏强缓存:文件内容变了→Hash 变了→URL 变了→浏览器认为是新文件,重新下载。
协商缓存:浏览器发请求问服务器资源是否更新。Hash 能配合协商缓存,在文件内容不变时复用缓存,减少请求次数。
简单说:Hash 是为了实现「内容变了强制更新,内容不变永久缓存」的精准控制。
SSO(Single Sign-On,单点登录):
在多个互信的关联系统中,用户只需登录一次,就能在所有系统中自动登录,无需重复输入账号密码。
核心原理:统一认证中心 + 令牌(Token/Ticket)共享。
访问系统 A
Ticket 跳转回系统 A。Ticket 去认证中心验证,验证通过后,系统 A 建立局部会话,用户登录成功。访问系统 B
Ticket。Ticket 验证,通过后建立局部会话,用户自动登录成功。