# js微任务和宏任务有哪些:
微任务:Promise.then、Promise.catch、promise.finally,Object.observe(已废弃)、MutationObserver。
宏任务:setTimeout、setInterval、I/O 操作, UI渲染
# event loop / js事件循环机制:
由于js是单线程的,为了不阻塞线程, js在设计之初将任务分为同步任务和异步任务, 异步任务被分为宏任务和微任务,
同步任务在主线程中执行,而异步任务者被放到任务队列中等待,
待主线程执行完同步任务后,再从任务队列中获取异步任务来执行,
每次调用栈清空后,会先检查并执行所有微任务,在执行宏任务,
如此循环往复
# 浏览器渲染原理/浏览器渲染机制:
浏览器会将html使用html解析器解析为htmldom树,将css使用css解析器解析为cssom,
然后进行样式计算,将CSS规则应用到DOM节点,构建成一个渲染树,
在构建完渲染树之后,浏览器会将每一个渲染对象就行布局计算,确定他们的位置和大小,
待布局完成后,浏览器将渲染对象转化为像素信息并绘制到屏幕上。
# 什么是重绘和重排?怎么减少浏览器重绘和重排?
重排是指当DOM的位置或尺寸发生变化时,浏览器需要重新计算元素的布局,以确保它们正确地显示在页面上。
重绘则是指元素外观发生变化时,浏览器重新绘制元素的外观,但不需要重新布局。
如何减少浏览器重绘和重排:
1.样式集中改变,避免逐个修改
2.使用absolute或fixed定位
3.减少DOM操作
4.使用CSS3动画和过渡效果,而不是JavaScript来改变元素的位置和尺寸
# nextTick的原理和作用?
原理: nextTick的实现依赖于JavaScript的事件循环和微任务队列。Vue 在内部会根据当前环境采用不同的异步实现策略:
如果当前环境支持Promise,则使用Promise.then和Promise.resolve来实现,将回调函数包装在Promise的then方法中,
并在当前任务执行完毕后放入微任务队列中。如果不支持Promise,
则会使用MutationObserver或其他宏任务如setTimeout作为备选方案。
作用: 确保在DOM更新完成后执行操作,从而获取最新的DOM状态
# diff了解过吗
Diff算法是虚拟DOM的核心优化机制,它通过『同级比较、Key复用、类型判断』三大策略,
降低树对比的复杂度,配合双端交叉对比和最长递增子序列等技巧,实现最小化的DOM更新,极大提升了前端框架的渲染性能。
# 什么是虚拟dom
虚拟DOM本质上是一个JavaScript对象树,它是对真实DOM的抽象,通过差异化对比最小化真实DOM操作,以提升渲染性能。
# $set 原理
由于vue2使用的是object.defineProperty,实现响应式,导致无法检测对象的属性新增和删除
使用$set内部会判断目标是否为数组,如果是就用splice触发更新,如果是对象,者调用defineReactive让属性变成响应式,
并手动 notify通知依赖更新
# 浏览器垃圾回收机制:
浏览器的垃圾回收机制是一种自动管理内存的机制,它通过标记-清除算法来识别和回收不再使用的内存。
具体来说,垃圾回收器会定期从根对象(如全局变量、活动函数的作用域)出发,标记所有可达的对象,
然后清除那些未被标记的不可达对象。为了提升效率,现代浏览器采用分代收集策略,将内存分为新生代(频繁回收短期对象)
和老生代(较少回收长期存活对象),并通过增量回收方式拆分任务,减少页面卡顿。开发者的核心任务是避免内存泄漏,
确保不再需要的对象及时脱离引用关系。
# vue3和vue2区别,做了哪些性能优化:
Vue 3 相较于 Vue 2 是一次全方位的架构升级。vue3采用 Proxy 重构了响应式系统,解决了 Vue 2 中
Object.defineProperty 无法检测对象属性增删等限制,性能显著提升。vue3引入了 Composition API,
允许基于逻辑功能组织代码,解决了 Vue 2 的 Options API 在复杂组件中逻辑分散的问题。
Vue 3 支持多个根节点的 Fragment 模板、提供 Teleport 等内置组件、并通过更好的 Tree-shaking 机制减小了打包体积。
# webpack和vite的区别:
Webpack 的构建理念是「打包构建」,Vite 是「按需编译」。
Webpack 会先打包所有模块生成 Bundle,再启动开发服务器,项目越大启动越慢;
Vite 则利用浏览器原生 ES 模块支持,在开发时直接按需编译源文件,启动速度极快。
Vite 开发更轻量,Webpack 生态成熟、功能全面,更适合复杂定制场景。
# 冒泡排序:
void Func(int[] array)
{
if (array != null && array.Length > 0)
{
for (int i = 0; i < array.Length - 1; i++)
{
for (int j = 0; j < array.Length - i - 1; j++)
{
if (array[j] > array[j + 1])
{
int tem = array[j + 1];
array[j + 1] = array[j];
array[j] = tem;
}
}
}
}
}
# 手写防抖函数
function debounce(func, delay) {
let timeout;
return function(...args) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, delay);
}
}
# 手写节流函数
function throttle(func, delay) {
let flag = true;
return function(...args) {
if (!flag) return;
flag = false;
setTimeout(() => {
func.apply(this, args);
flag = true;
}, delay);
}
}
# 手写事件总线
class EventBus {
constructor(){
this.events = {}
}
on(name,callback){
if(!this.events[name])
this.events[name] = []
this.events[name].push(callback)
}
emit(name,...arge){
if(this.events[name])
this.events[name].forEach(callback => callback(...arge))
}
off(name,callback){
if(this.events[name])
this.events[name] = this.events[name].filter(r => r != callback)
}
}