目录
1.项目第一次加载太慢优化 / vue 首屏加载过慢如何优化
ES6(ES2015)之后,JavaScript 新增了许多实用的数组和对象方法,下面为你详细介绍:
XSS:攻击者通过注入恶意脚本,在用户浏览器中执行,窃取 Cookie、会话令牌等敏感信息
6.在项目中,webpack使用过哪些常见的plugin(插件)和loader(加载器)
Vite 的 Bundleless 工作流程(Bundleless(无打包模式) 是一种 不需要预先进行代码打包,直接利用 浏览器 ESM 机制 进行模块加载的开发模式。)
1.项目第一次加载太慢优化 / vue 首屏加载过慢如何优化
首屏加载慢的常见原因,比如有打包后的文件过大、资源加载顺序不合理,素材资源一次性加载过多等等。
- 首先从代码层面优化,路由懒加载,分模块加载文件,合理使用路由懒加载可使首屏 JS 体积减少 40%-60%,然后对于工具库,尽量采用按需引入的方式。然后合理使用v-if和v-show,合理使用watch和computed,使用v-for必须添加key
- 然后从资源层面优化,图片压缩(Squoosh)+ WebP 格式 + 懒加载(Intersection Observer),优先使用字体图标,大文件放在cdn上,比如阿里云七牛云
- 然后构建配置优化,使用骨架屏,开启Brotli 、gzip压缩代码,减少代码包的大小,使用Tree Shaking移除 JavaScript 上下文中未被引用代码(它通过分析代码中的导入(import)和导出(export)语句,判断哪些代码是 “活的”(被引用),哪些是 “死的”(未被引用),从而在打包时剔除 “死代码”。作用:大幅减少打包后的代码体积,提升应用加载速度,尤其对使用大型第三方库的项目优化效果显著。)
2.如何解决页面请求接口大规模并发问题
如何解决页面请求接口大规模并发问题,不仅仅包含了接口并发,还有前端资源下载的请求并发。个人认为可以从以下几个方面来考虑如何解决这个问题:
- 合并请求,将所有首屏需要依赖的接口,聚合为一个接口
- 后端优化,可以对接口进行优化,采用缓存技术,对数据进行预处理,减少数据库操作等。另外可以使用反向代理,负载均衡等技术,分担服务器压力。
- cdn加速,使用cdn缓存技术减少服务器请求压力,提高网站访问速度。(CDN 服务器采用缓存技术,当用户首次请求某个资源时,CDN 会从源服务器获取该资源,并将其缓存到本地。后续再有其他用户请求相同资源时,CDN 会直接从本地缓存中提供该资源,而无需再向源服务器发起请求。)
- 使用websocket建立一个持久连接,避免反复连接请求。
- 使用浏览器缓存技术:强缓存,协商缓存,离线缓存,
Service Worker
等(Service Worker
是一种运行在浏览器后台的脚本,它可以拦截网络请求,实现离线缓存、消息推送等功能) - 聚合一定量的静态资源,比如提取公共代码,对图片进行雪碧图处理,多张图只下载一张图片
3.说说了解的es6-es10的东西有哪些
块级作用域:let/const 解决 var 的变量提升和闭包问题
箭头函数(Arrow Functions)绑定外层 this,简化回调
类(Class)语法糖:基于原型链的面向对象封装
模块(ES Module)标准化导入导出
解构赋值(Destructuring)、扩展运算符
ES6(ES2015)之后,JavaScript 新增了许多实用的数组和对象方法,下面为你详细介绍:
- Array.from():可将类数组对象或可迭代对象转换为真正的数组。
- Array.find():返回数组中满足提供的测试函数的第一个元素的值,否则返回 undefined。
- Array.findIndex():返回数组中满足提供的测试函数的第一个元素的索引,若没有找到则返回 -1。
- Object.assign():用于将一个或多个源对象的所有可枚举属性复制到目标对象,返回目标对象。
- Object.keys():返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。
- Object.values():返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for...in 循环的顺序相同。
4.常见前端安全性问题
前端安全的主要领域,比如 XSS、CSRF、SQL 注入(虽然更多是后端,但前端也可能涉及)、点击劫持、跨域问题、密码安全、文件上传安全等等。然后,每个领域下有哪些常见的问题,比如 XSS 的类型、预防措施,CSRF 的原理和防护方法,这些都是面试中常问的。
XSS:攻击者通过注入恶意脚本,在用户浏览器中执行,窃取 Cookie、会话令牌等敏感信息
预防措施:1.输入输出转码,对用户输入(如表单、URL 参数)和输出(如 HTML、URL、JavaScript)进行编码(如使用textContent代替innerHTML 2.Cookie 安全属性:设置HttpOnly(防止 JS 读取 Cookie)、Secure(仅 HTTPS 传输)
跨站请求伪造(CSRF)
攻击者诱导用户执行非自愿的操作(如转账、修改密码),利用用户已登录的会话凭证。
攻击原理:用户登录 A 网站后,浏览器携带 Cookie 访问恶意网站 B,B 向 A 发送伪造请求(如隐藏的表单提交或自动发送的 GET 请求)。
防御措施:Token 验证:提交时校验 Token 与用户会话是否匹配。设置Cookie
的SameSite=Strict/Lax
,限制跨站请求携带 Cookie(Strict
完全禁止,Lax
允许部分安全场景)。
跨域资源共享(CORS)与安全
限制允许的源:使用Access-Control-Allow-Origin
指定单一可信域名(如https://api.example.com
),避免使用*
(通配符)。
预检请求(Preflight):对复杂请求(如含Content-Type: application/json
的 POST 请求),浏览器先发送 OPTIONS 请求验证权限,需确保服务端正确响应。
前端如何处理密码安全?需要
- 输入强度校验:通过正则表达式检查密码复杂度(如大小写、数字、特殊字符,长度限制)。
- 掩码显示:使用
input type="password"
隐藏输入内容,避免明文泄露。 - 避免本地存储:绝不将密码明文存储在
localStorage
/sessionStorage
或 Cookie 中(应通过 HTTPS 传输,由后端加密处理)。 - 防暴力破解:前端配合后端限制登录尝试次数,或添加验证码。
如何避免 URL 中的敏感信息泄露?
- 避免明文参数:绝不通过 URL 传递密码、Token 等敏感信息(如
https://api.com/login?token=xxx
),应通过 POST 请求体或 Header 传输。 - URL 编码:对用户输入的参数进行编码(如
encodeURIComponent
),防止特殊字符导致的注入攻击(如路径遍历../
)。 - 路由参数校验:对动态路由参数(如
/user/123
)进行合法性校验,防止越权访问(如篡改 ID 访问他人数据)。
其他常见安全问题
如何理解 Web 安全中的 “同源策略”?它的作用是什么?答:浏览器限制不同源(协议、域名、端口均相同)的页面之间交互,防止恶意网站窃取数据,作用是:阻止跨域读取 Cookie、DOM、AJAX 请求,是浏览器的核心安全机制。
什么是依赖项安全?如何防范 npm 包的漏洞?答:避免使用未维护的库,选择下载量高、社区活跃的包。使用
package-lock.json
或yarn.lock
锁定依赖版本,防止版本劫持。简述 HTTPS 的作用及前端相关配置 :作用:加密传输数据,防止中间人攻击、数据篡改和窃听。确保证书有效(非自签名),使用 HSTS(HTTP Strict Transport Security)头强制浏览器仅通过 HTTPS 连接。
总结:前端安全核心原则
- 输入输出校验:永远不信任用户输入,对所有输入进行严格过滤和转义。
- 最小权限原则:限制资源访问范围(如 CORS、CSP),避免过度开放权限。
- 关注最新漏洞:定期学习 XSS、CSRF、依赖漏洞等最新攻击手段及防御方案(如 2023 年的 CORS 漏洞
confusion attacks
)。
5.vite和webpack在热更新上有啥区别
1.实现机制,vite使用浏览器原生的ES模块导入功能,可以实现模块级别的热更新,即只更新修改的模块,而不需要刷新整个页面。这样可以提供更快的开发迭代速度。而在webpack中,热更新是基于文件级别的,Webpack 会对整个项目进行打包,需要重新构建并刷新整个页面。(Webpack 的热更新(HMR,Hot Module Replacement)机制不依赖特定的模块导入规范,而是通过 HotModuleReplacementPlugin
插件和 开发服务器(如 webpack-dev-server)实现,其核心原理是在模块更新时,通过注入运行时代码来替换旧模块)
2.热更新速度,由于 Vite 在开发环境下不需要打包,所以热更新速度非常快。当修改一个模块时,Vite 只需要重新编译该模块,并将更新后的模块发送给浏览器,几乎可以实现即时更新。而webpack 需要重新编译整个模块或部分相关模块,然后再将更新后的代码推送给浏览器。尤其是在项目规模较大、依赖关系复杂时,重新编译的时间会明显增加。
综上所述,Vite 在热更新方面具有速度快、配置简单等优势,更适合现代前端开发的快速迭代需求;而 Webpack 虽然热更新配置相对复杂,但它的生态系统成熟,对于复杂项目的热更新也能提供有效的支持。
6.在项目中,webpack使用过哪些常见的plugin(插件)和loader(加载器)
Loader 主要专注于文件的转换,将不同类型的文件转换为 Webpack 可处理的模块;而 Plugin 的功能更广泛,可在 Webpack 构建过程的各个阶段执行各种任务。
Loader(加载器)
- 作用:Loader 的功能就是对不同类型的文件(如 CSS、图片、字体等)进行转换,让 Webpack 能够理解并处理这些文件。简单来说,Loader 就是将非 JavaScript 文件转化成 Webpack 可处理的模块。
- 使用方式:在 Webpack 配置文件里,借助
module.rules
属性来配置 Loader。每个规则包含test
和use
两个关键属性,test
用于匹配文件类型,use
用于指定要使用的 Loader。 - 示例:处理 CSS 文件时,一般会用到
style-loader
和css-loader
。css-loader
的作用是解析 CSS 文件里的@import
和url()
语句,style-loader
则把 CSS 代码注入到 HTML 文件的<style>
标签中。
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
Plugin(插件)
- 作用:Plugin 能够在 Webpack 构建过程的各个阶段执行特定的任务,它的功能更为广泛,可用于优化打包结果、管理资源、注入环境变量等。
- 使用方式:在 Webpack 配置文件里,通过
plugins
属性来配置 Plugin。首先要引入 Plugin,接着在plugins
数组里创建 Plugin 实例。 - 示例:
HtmlWebpackPlugin
可自动生成 HTML 文件,并把打包后的 JavaScript 文件注入其中。
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
常用loader
css-loader
:解析 CSS 文件里的@import
和url()
语句,把 CSS 文件转化为 JavaScript 模块。less-loader
:将 Less 文件编译成 CSS 文件,同样常与css-loader
、style-loader
配合。file-loader
:处理文件资源,像图片、字体等,将文件复制到输出目录,并返回文件的公共 URLbabel-loader
:借助 Babel 将 ES6 + 代码转换为向后兼容的 JavaScript 代码,以确保在旧版本浏览器中也能正常运行。
常用plugin
HtmlWebpackPlugin
:自动生成 HTML 文件,并且把打包后的 JavaScript 和 CSS 文件注入到 HTML 文件中。TerserPlugin
:压缩和混淆 JavaScript 代码,减少文件大小,提高加载速度。CopyWebpackPlugin
:将指定的文件或目录复制到输出目录,适用于处理静态资源。MiniCssExtractPlugin
:将 CSS 提取到单独的文件中,而非将其注入到 JavaScript 文件里,从而提升性能。
7.vite常见面试题
Vite 核心特性
- 原生 ES 模块(基于浏览器 import)
- HMR 超快(只更新变化部分)
- 按需加载(不需要打包)
- 生产模式使用 Rollup
- 内置 TypeScript、PostCSS、Vue、React 支持
如何指定 vite 插件 的执行顺序?
可以使用 enforce
修饰符来强制插件的位置:
pre
:在 Vite 核心插件之前调用该插件- 默认:在 Vite 核心插件之后调用该插件
post
:在 Vite 构建插件之后调用该插件
Vite 的 Bundleless 工作流程(Bundleless(无打包模式) 是一种 不需要预先进行代码打包,直接利用 浏览器 ESM 机制 进行模块加载的开发模式。)
- 解析
index.html
- Vite 直接以 HTML 作为入口文件,解析其中的
<script type="module">
。
- Vite 直接以 HTML 作为入口文件,解析其中的
- 按需加载 ES Modules
- 浏览器遇到
import
语句时,Vite 直接返回相应的模块,而不是像 Webpack 那样打包整个项目。
- 浏览器遇到
- ESBuild 预编译
.ts
、.jsx
、.vue
等文件被 Vite 即时转换,只处理被请求的文件,不影响其他部分。
- HMR 热更新
- 代码改动后,Vite 只更新受影响的模块,而不是整个页面。
8.大文件上传
流程:
1.获取文件元数据->2.文件切片->3.计算分片Hash与文件hash->4.检查文件是否已经上传过->5.检查需要上传的文件分片->6.上传需要上传的分片->7.待全部分片上传完成后校验分片->8.合并分片
文件切片 :
切片核心是利用Blob.prototype.slice方法,和数组slice方法类似,文件的slice方法可以返回原文件的切片,同时利用webwork结合spark-md5去计算文件hash值
断点上传:
所谓断点上传(又名恢复上传)就是某个文件已经把部分切片上传到后端且保存,但是在上传过程中出现了一些不可预知问题:例如网络中断、超时、不小心刷新了页面等等,会导致上传中断,但是我们又不想再一次把所有切片又上传一次,只要把未上传的切片上传给后端即可
暂停上传:
其实就是把还在请求中的接口直接中断。这时候我们就可以用到axios
的AbortController
方法去取消接口请求,(原生XMLHttpRequest 使用 abort
方法)
并发上传:
设定一个并发数限制,代表同时可执行的上传任务数量。例如,设置并发数为 3,表示同一时间最多有 3 个切片在上传。利用一个变量来记录当前正在执行的上传任务数量,每次启动一个新的上传任务时,该变量加 1;任务完成(成功或失败)后,该变量减 1。
9.JS执行100万个任务,如何保证浏览器不卡顿
JavaScript 是单线程的,这意味着同一时间只能执行一个任务。在浏览器环境下,这个单线程要负责处理多种事务,如执行 JavaScript 代码、处理用户交互以及更新 DOM 等。
当你一次性执行 100 万个任务时,这 100 万个任务会依次在主线程中排队等待执行。在这些任务执行期间,主线程会被完全占用,无法去处理其他事务。例如,当用户点击按钮时,由于主线程正在忙于执行那 100 万个任务,无法响应这个点击事件,从而让用户感觉浏览器卡顿甚至失去响应。
为了避免这种情况,就需要采用一些技术手段,如使用 Web Workers、requestAnimationFrame
或定时器等,将任务分割成小任务,在不阻塞主线程的情况下逐步执行。
- Web Workers将任务移到单独的线程中执行,避免阻塞主线程。
requestIdleCallback
是浏览器的API,可以在主线程空闲时执行非紧急任务。能高效利用主线程的空闲时间,而不会影响页面卡顿requestAnimationFrame
:会在浏览器下次重绘之前执行回调函数。浏览器的重绘频率通常是每秒 60 帧(FPS),也就是大约每 16.67 毫秒重绘一次。因此,使用requestAnimationFrame
能保证回调函数以稳定的帧率执行,适合处理与动画、渲染相关的任务。
10.事件循环机制概述
JavaScript 是单线程的,它通过事件循环(Event Loop)来处理异步操作。事件循环主要负责协调调用栈(Call Stack)、宏任务队列(Macrotask Queue)和微任务队列(Microtask Queue)的工作。执行顺序一般是:先执行调用栈里的同步代码,同步代码执行完后,检查微任务队列,将微任务队列中的任务依次取出执行,直到微任务队列为空;接着从宏任务队列中取出一个宏任务执行,执行完这个宏任务后,再次检查微任务队列,如此循环往复。
- 微任务:微任务会在当前调用栈清空后、下一个宏任务执行之前被执行。也就是说,只要微任务队列中存在任务,JavaScript 引擎就会持续从队列里取出任务并执行,直至微任务队列为空。
- 宏任务:宏任务在事件循环的特定阶段执行。每次事件循环开始时,会从宏任务队列中取出一个宏任务来执行,执行完毕后,会检查微任务队列,将微任务队列中的任务全部执行完,再接着处理下一个宏任务。
- 微任务:常见的微任务来源有
Promise
的then
、catch
、finally
回调,async/await
(本质基于Promise
实现)中await
之后的代码,MutationObserver
(浏览器环境),process.nextTick
(Node.js 环境)等。 - 宏任务:常见的宏任务来源有
setTimeout
、setInterval
、setImmediate
(Node.js 环境)、I/O
操作、UI rendering
(浏览器环境)等 - 微任务:适用于需要在当前操作完成后立即执行的异步操作,例如对
Promise
结果的处理,这样可以保证在当前同步代码执行完后马上处理异步结果,避免不必要的延迟。 - 宏任务:常用于需要延迟执行或者周期性执行的操作,比如定时器用于实现定时提醒、动画效果中的周期性更新等。