1. 页面上有100万个任务需要执行,如何保证页面不卡顿?
为了确保页面在执行大量任务时不卡顿,可以采用以下技术方案:
requestIdleCallback:浏览器提供的 API,在主线程空闲时执行任务,避免阻塞主线程。setTimeout:通过将任务拆分成小的异步块,使其在多个事件循环中执行。postMessage:使用postMessage将任务分发到其他线程或窗口,避免主线程的阻塞。Web Workers:将任务移至后台线程(Web Worker),不影响主线程的渲染,但不能直接操作 DOM。
2. 后端响应巨量数据,如何避免性能问题?
渲染性能优化:
- 分页:对大量数据进行分页,避免一次性加载过多数据。需要产品支持来进行分页策略设计。
- 分片渲染(React Fiber) :将渲染任务分片(通过
requestIdleCallback或setTimeout等方法),让浏览器保持响应,避免阻塞 UI 渲染。 - 虚拟滚动:只渲染用户当前视口内的数据,其它数据延迟加载。使用
react-virtualized或react-window等库。 - Canvas:适用于需要大量绘图但交互较少的场景,减少 DOM 操作的开销。
网络性能优化:
- 改接口规格:优化接口返回的数据格式,仅返回必要的数据,减少网络传输量。
- 流式读取:在响应返回过程中,逐步解析数据。类似浏览器解析 HTML 时的渐进式解析。
- SSE (Server-Sent Events) :使用服务器推送实时数据流,避免频繁的轮询。
- WebSocket:双向通信适用于实时数据传输,适合聊天应用、实时游戏等场景。
3. 死循环与无限递归的影响
死循环:
死循环会导致浏览器无响应,因为循环会一直占用主线程。通过将循环异步化(如使用 setTimeout 或 Promise)可以避免阻塞浏览器线程。
//设置异步
function delay(duration = 1000){
return new Promise(resolve => {
setTimeout(resolve, duration)
})
}
while(1){
await delay(0)
}
这段代码不会导致浏览器卡死,因为异步执行允许浏览器进行渲染和处理其他事件(浏览器渲染帧16.6毫秒,见缝插针执行任务)。
//设置异步
function delay(duration = 1000){
return new Promise(resolve => {
setTimeout(resolve, duration)
})
}
while(1){
//await 1
await Promise.resolve(1)
}
第一次宏队列里面执行。下一次的判断条件放到了微队列,优先级太高了,渲染帧为他让步,他一直再渲染帧之前执行,导致卡死。
无限递归:
无限递归会导致栈溢出错误,但如果递归函数本身是异步的,栈并不会立即增加,反而会被等待队列处理,从而避免栈溢出:
//设置异步
function delay(duration = 1000){
return new Promise(resolve => {
setTimeout(resolve, duration)
})
}
function m(){
await delay(0)
m()
}
不会爆栈,入栈过后立马出栈,等待的是延时队列,优先级不高,渲染帧可以见缝插针不会导致浏览器卡死。
4. Vue项目常见优化手段
- 路由和图片懒加载:按需加载路由和图片,减少初始加载时间。
- Suspense:用于异步组件的加载。
- v-if 与 v-show:根据需求选择合适的指令,
v-if用于条件渲染,v-show用于控制显示/隐藏。 - 打包优化:利用代码分割、Tree Shaking 减少最终的打包体积。
- 网络优化:使用 CDN 加速资源加载,支持 HTTP2、图片格式优化(如 WebP)、GZIP 压缩。
- 请求合并:通过批量请求减少请求数量。
- GraphQL:通过 GraphQL 解决 RESTful API 请求过多的问题。
- 组件优化:使用
computed缓存值,key优化虚拟 DOM 比较,避免组件不必要的重新渲染。 - keep-alive:缓存组件的状态,避免重复渲染。
- 函数式组件:减少组件的生命周期函数,提高渲染效率。
5. 如何实现手机与电脑访问同一 URL 时,分别显示移动端与 Web 端页面?
- 流式布局:使用百分比、
rem、flex、grid等相对单位设计响应式布局。 - 媒体查询:根据设备屏幕大小,使用 CSS 媒体查询来适配不同设备。
- 独立开发:为移动端与 Web 端分别开发独立页面,使用代理或重定向(如 302 状态码)来区分不同设备。
- (服务器判断请求头user-agent)
6. JavaScript 作用域类型
- 函数作用域:在函数内部定义的变量只在该函数内有效。
- 块级作用域:
let和const声明的变量具有块级作用域。 - 全局作用域:全局环境中的变量。
- 模块作用域:ES6 模块中的作用域。
- 脚本作用域:传统脚本中的作用域。
catch作用域:try...catch中,catch内部的变量在外部不可见。with和eval作用域:这两者会影响作用域链,避免过度使用。
7.跨域解决方案,真实项目如何选择?
重要的是生产环境和开发环境要保持一致
1.生产环境跨域只能用cros,开发环境也得用cros
2.生产环境不存在跨域开发环境上代理
8.打印顺序?
-
宏任务(
setTimeout):1。 -
微任务(
Promise):6和4。 -
控制台:2,3,5,6,4,1
setTimeout(function () {
console.log(1);
}, 0);
const p = new Promise((resolve) => {
console.log(2);
for (var i = 0; i < 10000; i++) {
i == 9999 && resolve();
}
});
Promise.resolve().then(() => {
console.log(6);
});
console.log(3);
p.then(function () {
console.log(4);
});
console.log(5);