基础
JS
HTML & CSS
移动端
- 移动端如何做兼容、性能优化?
移动端做兼容,主要考虑以下几方面:
- 了解不同设备和浏览器(Safari、Chrome等)以及发布版本的功能兼容,识别并测试;
- 适配不同分辨率和屏幕尺寸:使用响应式布局和弹性盒模型等技术、媒体查询配置等;
- 处理移动端特有事件和API:触摸事件等、利用检测库来判断设备是否支持特定API或者功能等;
- 考虑不同操作系统的兼容性:使用框架提供的组件和API,简化跨平台开发的复杂性;
- 测试和修复兼容性问题:通过模拟器、真机模拟等方式;
性能优化:
- 减少网络请求:合并、压缩文件、使用缓存策略等,减少请求次数、减少重复请求;
- 优化UI渲染:减少DOM操作次数、优化图片加载和使用,使用合适的图片格式、压缩图片、懒加载等技术;
- 使用缓存:缓存一切可缓存资源,使用长Cache策略,通过时间戳等方式更新缓存资源;
- 压缩HTML、CSS、JS等文件;
- 优化首屏加载:按需加载;
- 性能监测和优化:使用性能分析工具(如Chrome开发者工具、Safari Web Inspector等)监测应用的性能瓶颈;合理管理和释放资源,避免内存泄漏和性能下降;
- 更新和维护:定期进行性能评估和优化,及时更新和保持设备应用兼容性和用户体验。
Vue部分
Vue是如何收集依赖的
Vue依赖收集发生在defineReactive()方法中,在方法内new Dep()实例化一个Dep()实例,然后在getter中通过dep.depend()方法对数据依赖进行收集,然后在setter中通过dep.notify()通知更新。整个Dep其实就是一个观察者,把收集的依赖存储起来,在需要的时候进行调用。在收集数据依赖的时候,会为数据创建一个Watcher,当数据发生改变通知每个Watcher,由它来进行更新渲染。
webpack
react部分
- vue和react的相同点和不同点
- react keep-alive是怎么做的?
- react生产问题怎么定位到具体错误代码行数?
- vue和react源码用了哪些设计模式
- react页面白屏检测
网络
环境配置
- 用nginx处理过什么问题,高并发怎么解决,如何控制用户的访问量?
- nginx使用场景是什么?反向代理如何使用?图片防盗链如何做?
- docker如何配置CI、CD?
- 如何用jenkins完整跑一个CI、CD(搭建项目至投入生产)?
- cdn用的那个厂商的,怎么配置缓存策略
- 性能埋点,有哪些点需要获取?
- JavaScript 错误:捕获 JavaScript 运行时错误,例如语法错误、引用错误等。
- 网络错误:捕获网络请求失败的情况,例如 HTTP 状态码 404、500 等。
- 用户交互异常:捕获用户与页面交互时的异常情况,例如表单提交失败、按钮点击无响应等。
- 浏览器兼容性问题:捕获不同浏览器版本或设备上可能出现的兼容性问题。
- 资源加载异常:捕获图片、字体、样式表等资源加载失败的情况。
实操题
- 后端200M数据渲染在页面卡顿如何解决?一屏展示不下呢?
- 通过
requestAnimationFrame+fragment时间分片;
requestAnimationFrame也是个定时器,时间取决于当前电脑的刷新率,60HZ则16.7ms执行一次;document.createDocumentFragment()创建时间分片,最后回流挂载在ul上。
- 虚拟列表:获取所有数据,获取可视区高度,计算数据分片展示;
// 可视区放下多少个li
const itemNum = computed(() => {
return ~~(boxHeight.value / itemHeight.value) + 2
})
const startIndex = ref(0) // 索引
// 页面滚动
const doScroll = () => { // div内部滚动距离 / 每项的高度 = 滚了多少项
const index = ~~(scrollBox.value.scrollTop / itemHeight.value)
if (index === startIndex.value) return // 滚到最开始的位置
startIndex.value = index // 可视区的第一条数据下标
}
const endIndex = computed(() => { // 可视区最后一个下标
let index = startIndex.value + itemNum.value * 2 // 考虑用户体验,准备可视区一倍的li
if (!allList.value[index]) { // 已经滚超了,回来一个位置
index = allList.value.length - 1
}
return index
})
const currentList = computed(() => {
let index = 0
if (startIndex.value <= itemNum.value) { // [0, 21] [0, 22] …… [0, 30] [1, 31]
index = 0
} else {
index = startIndex.value - itemNum.value
}
return allList.value.slice(index, endIndex.value + 1)
})
// 根据当前可见区域前后的空白区域高度,动态计算样式,确保滚动的平滑性
const blankStyle = computed(() => {
let index = 0;
if (startIndex.value <= itemNum.value) {
index = 0;
} else {
index = startIndex.value - itemNum.value;
}
return {
paddingTop: index * itemHiehgt.value + "px",
paddingBottom: (allList.value.length - endIndex.value - 1) * itemHiehgt.value + "px"
};
});
- 怎么做的主应用或子应用单独启动
- 子应用单独启动情况下怎么获取主应用的cookie信息
- 业务的页面卡顿怎么解决
- 实际业务大数据量DOM渲染优化
- 自研自动化打包部署脚本
- 如何实现大文件上传
Blob上自带一个slice方法:Blob.slice(起始字节, 最终字节),返回Blob对象。将切片文件数组数据转换为表单格式传给后端,通过Promise.all并发发给后端,传输完毕后发送一个合并请求,带上文件名和切片大小信息。
问题:
- 耗时长;
- nginx反向代理映射时间超时;
- 无法得知上传进度,无法暂停;
解决办法:分片上传
// 切片数量需要和后端协商具体最大切片数做计算
const createChunk = (file, size = 2 * 1024 * 1024) => {
const chunkList = [] // 切片
let cur = 0 // 切的进度
// 循环切
while (cur < file.size) {
chunkList.push({ file: file.slice(cur, cur + size) })
cur += size
}
return chunkList
}
// 上传切片
const uploadChunks = () => {
const formateList = uploadChunkList.value.map(({ file, fileName, index, chunkName }) => {
// 对象需要转成二进制数据流进行传输
const formData = new FormData() // 创建表单格式的数据流
// 将切片转换成了表单的数据流
formData.append('file', file)
formData.append('fileName', fileName)
formData.append('chunkName', chunkName)
return { formData, index }
})
const requestList = formateList.map(({ formData, index }) => {
// axios[method](url, data, { headers, onUploadProgress })
return requestUpload({
url: 'http://localhost:3000/upload',
data: formData,
onUploadProgress: createProgress(uploadChunkList.value[index]) // 进度条函数拿出来写
})
})
// 合并切片请求
Promise.all(requestList).then(mergeChunks())
}
其它
- 万一某一切片上传失败,怎么处理?—— 捕获索引,提示,或者重新上传;
- 一旦断网就要重新上传,如何解决?—— 断点续传
- http2.0特性,头部压缩怎么实现的
- csrf从前后端角度实现预防,你说的是常规的方案,要实现完全预防怎么做
- 项目是否用到typescript
- 项目是否用到自动化测试
- 302怎么确定重定向路径
- promise(A).catch(f1).then(f2),f1执行后f2回执行吗,为什么
new String('123')和String('123')有什么区别?new String('123')==String('123')吗,typeof判断这两个是什么?
手写题
- 手写
Promise.all - 正则路径匹配
const reg = /\.js$/; // 匹配js文件:以.js结尾
console.log(reg.test('/sd/abc.js')); // 输出true
// `(\d+)`是一个捕获组,它匹配一个或多个数字,并将匹配的结果保存在结果数组的索引1中(索引0是整个匹配的结果)
const regURL = /^\/users\/(\d+)\/profile$/;
console.log(regURL.test('/users/23/profile')); // 输出true
const res = regURL.exec('/users/123/profile')
console.log('ID: ' + res[1]); // 输出:ID: 123
- 解析URL的query信息,转换为对象形式
const url = 'https://www.baidu.com/abc?a=1&b=2&c#hash';
Object.fromEntries((new URL(url)).searchParams.entries());
- 手写对象扁平化
- 手写eventloop时序考察
- 手写全排列
- 手写防抖
- 手写快排
- 实现字符串前缀匹配
- 版本号比较
- 正则写13-15位大写字母或数字
- 三个页面地址为www.baidu.com/a,www.baidu.com/b,www.qq.com, sessionStorage是否能在这些页面共享,为什么 localstorage呢
- 有效括号匹配
- 判断b是否是a的子集(a和b有重复元素,要求b的同个元素出现次数<=a的同个元素出现次数)
- js对象数组转树形结构
- 将某一串数字,转为财务格式,千分位加逗号。例如:2345.6 =》2,345.6
const reg = /\B(?=(\d{3})+(?!\d))/g
const num = 2345.6
console.log(num.replace(reg, ','))
其它
-
登录鉴权是如何做的
-
Linux命令考察
-
docker是怎么实现选取镜像并启动容器
-
cicd的理解和具体实现
-
实现一个单据功能的接口数据传输格式,从后端角度考虑为什么要这么传
-
如果重构系统,你会怎么做?
-
大数据业务理解?埋点怎么做的?
-
多窗口通信怎么做?
-
proxySandbox和legacySandbox那个更好,为什么
-
legacySandbox会存在变量污染吗
-
legacysanbox是完全隔离吗,怎么实现完全隔离,在IE浏览器下怎么实现
-
setState是同步还是异步,为什么?
-
树摇原理,编译阶段怎么确定代码是否引用,怎么确定要不要删除的
-
input怎么确定scheme结构?
-
scheme是什么?
-
webassembly了解过吗
-
数据大屏如何做响应式?
-
算法会哪些?
-
时间复杂度和空间复杂度怎么理解
-
redis nginx场景题
-
nginx try_files具体怎么使用
-
redis和k8s使用场景举例