知识点总结

77 阅读30分钟

1. 防抖和节流:

  1. 防抖: 单位时间内, 频繁触发事件, 只执行最后一次.
  • 例如搜索框中频繁输入内容、频繁点击按钮触发某个事件、监听用户缩放浏览器的resize事件
  1. 节流: 单位时间内, 频繁触发事件, 只执行第一次,
  • 例如高频点击事件,新增修改时提交表单,点提交后按钮置灰防止多次点击提交多次

2. js基础数据类型

  • 基本数据类型:string(字符串)、number(数字)、boolean(布尔)、null(空)、undefined(未定义)、symbol(符号)、bigint (长整形,处理高精度)
  • 引用数据类型:object(对象,除了基本数据类型其他都是对象。数组是对象、函数是对象、正则表达式也是对象)

3.数据类型检测的方式

1. ​​typeof 运算符​​

截屏2025-10-02 下午2.26.00.png

console.log(typeof 42); // "number"
console.log(typeof null); // "object"(需注意)

2.instanceof确判断对象的类型,只能判断引用类型不能判断基本数据

截屏2025-10-02 下午2.33.05.png

    2 instanceof Number // false
    'str' instanceof String // false
    true instanceof Boolean // false
    [] instanceof Array // true
    {} instanceof Object // true
    function(){} instanceof Function // true

3.Object.prototype.toString.call()

截屏2025-10-02 下午2.57.18.png 4. ​专用检测方法

截屏2025-10-02 下午3.00.21.png

截屏2025-10-02 下午3.06.04.png

截屏2025-10-02 下午3.06.44.png

截屏2025-10-02 下午3.07.18.png

4.call,aply,bind三者有什么区别?

都是改变this指向和函数的调用,call和apply的功能类似,只是传参的方法不同

  • call方法传的是一个参数列表
  • apply传递的是一个数组
  • bind传参后不会立刻执行,会返回一个改变了this指向的函数,这个函数还是可以传参的,bind()()
  • call方法的性能要比apply好一些,所以call用的更多一点

截屏2025-10-02 下午3.20.55.png 截屏2025-10-02 下午3.49.19.png

const person = {
  name: '王五'
};

function greet(age, city) {
  console.log(`你好,我是${this.name},今年${age}岁,来自${city}`);
}

greet.apply(person, [30, '上海']);
// 输出:你好,我是李四,今年30岁,来自上海

greet.call(person, 25, '北京');
// 输出:你好,我是张三,今年25岁,来自北京

// 创建一个新函数,this 指向 person
const boundGreet = greet.bind(person, 28);
boundGreet('广州');
// 输出:你好,我是王五,今年28岁,来自广州

5.$nextTick原理

nextTick是vuejs的一个异步执行方法,的核心是利用了如Promise、MutationObserver、setImmediate、setTimeout等原生JavaScript方法来模拟对应的微/宏任务的实现,本质是为了利用JavaScript的这些异步回调任务队列来实现Vue框架中自己的异步回调队列。

$nextTick 的本质是将回调函数延迟到下次 DOM 更新周期之后执行。Vue 通过异步队列和任务调度机制来实现这一功能。

  • data改变之后,DOM不会立即渲染
  • $nextTick会在DOM渲染之后被触发,以获取最新的DOM节点

在绝大多数情况下,nextTick 是微任务 vue2中浏览器不支持也可能降级为宏任务,vue3里就是微任务

截屏2025-10-02 下午4.16.45.png

6.原型链

截屏2025-10-02 下午7.44.32.png

  • 原型和原型链设计的主要目的是实现继承,它通过对象之间的原型关联形成一条链式结构,让对象之间可以共享属性和方法。
  • 原型链: 当访问一个对象的属性或者方法时,若自身对象没有,JS会沿着prototype向上查找原型对象,直到找到或者到达原型链的终点(null)
  • 隐式原型__proto__,每个对象(除null外)都有一个内置的prototype属性,它可以通过__proto__访问,指向了构造函数的原型(prototype)。
  • 原型就是一个普通对象,它是为构造函数的实例共享属性和方法;所有实例中引用的原型都是同一个对象
  • 使用prototype可以把方法挂在原型上,内存值保存一份

截屏2025-10-02 下午8.08.02.png

截屏2025-10-02 下午8.08.27.png

7.闭包

截屏2025-10-04 下午3.10.02.png

  • 形成条件:
    1. 有一个外部函数,
    2. 内部函数引用了外部函数的变量,
    3. 内部函数被外部函数返回并在外部调用
  • 作用:
    1. 创建私有变量(数据封装) 变量 secret 是“私有”的,被安全地封装在 outer 函数内部,外部代码无法直接修改它,只能通过返回的inner方法来间接影响它。这保证了数据的完整性和安全性。
// 条件1:函数嵌套
function outer() {
  const secret = '秘密数据';
  
  // 条件2:内部函数引用外部变量
  function inner() {
    console.log(secret); // 引用外部变量
  }
  
  // 条件3:内部函数被返回或在外部使用
  return inner;
}

const myClosure = outer();
myClosure(); // 输出: "秘密数据"

解决闭包的内存泄漏,一个闭包不被需要时,可手动解除对他的引用,
例如将持有闭包的变量设为null
ex: myClosure = null

关键概念:可达性

  • 从全局作用域出发,可以通过引用链访问到的值,就是“可达的”。
  • 如果某个值变得“不可达”,它就会被回收。
  • 当一个外部函数执行完毕后,正常情况下,它的整个作用域(包括所有局部变量)都应该变得“不可达”,从而被垃圾回收。但是,如果这个外部函数内部定义的内部函数(闭包)被外部引用,并且这个内部函数使用了外部函数的变量,那么整个这个外部函数的作用域就会被保留下来,无法被回收。

8.强缓存和协商缓存

  1. 强缓存 Expires有效期,catch-control(no-cache;max-age=3600,缓存1小时)缓存机制
  2. 协商缓存 Etag 16进制的标志位,Last-modified 最后修改时间
  3. 区别
  • 强缓存(Strong Caching)和协商缓存(Conditional Caching)是浏览器缓存资源的两种核心机制,旨在减少网络请求、提升页面加载速度并降低服务器负载。
  • 强制缓存:强缓存允许浏览器在资源未过期时直接使用本地缓存,无需与服务器通信
    • 浏览器根据响应头中的 Expires 或 Cache-Control 字段判断资源是否过期。若未过期,直接从本地加载资源,不发送请求
  • 协商缓存:协商缓存则在强缓存失效后,浏览器和服务器请求,询问资源是否更新,通过服务器验证来决定是否使用缓存。
    • 服务器通过比较响应头(如 Last-Modified 或 ETag)决定资源是否更新:若未更新,返回 304 Not Modified,浏览器使用缓存;若更新,返回新资源

9. 不同的iframe间怎么通信

  1. postmessage:跨域iframe通信
    • 发送消息:
// 语法:targetWindow.postMessage(message, targetOrigin)
// 父页面向子 iframe 发送消息
const iframe = document.getElementById('myFrame');
iframe.contentWindow.postMessage(
    { 
        type: 'FROM_PARENT', 
        data: { message: 'Hello from parent' },
        timestamp: Date.now()
    },
    'https://child-domain.com' // 目标域,建议明确指定
);

// 子 iframe 向父页面发送消息
window.parent.postMessage(
    {
        type: 'FROM_CHILD',
        data: { message: 'Hello from child' },
        id: 'unique-message-id'
    },
    'https://parent-domain.com'
);
  • 接收消息:消息监听器 , 根据消息类型处理
 // 父页面接收子iframe的消息
  window.addEventListener('message', (event) => {
    if (event.data.type === 'MSG_FROM_CHILD') {
      console.log('子iframe说:', event.data.data);
    }
  });
  // 子iframe接收父窗口消息
  window.addEventListener('message', (event) => {
    if (event.data.type === 'MSG_FROM_PARENT') {
      console.log('父窗口说:', event.data.data);
    }
  });

2. window.topwindow.parent:同源iframe通信

  • 子 iframe直接通过window.topwindow.parent访问父窗口的变量或者方法
  • 父页面访问子 iframe:通过获取到目标iframe实例的contentWindow对象,来访问iframe中的变量、调用iframe中的方法、或者直接操作iframe的dom
//----子 iframe 访问父页面
// 在 iframe 内部
// 访问直接父窗口
const parentData = window.parent.someVariable;
window.parent.parentMethod();

// 访问顶级窗口
const topData = window.top.someVariable;
window.top.topMethod();

//-----**父页面访问子 iframe:**---------
<!-- 父页面 -->
<iframe id="myFrame" src="child.html"></iframe>
<script>
// 获取 iframe 的 window 对象
const frameWindow = document.getElementById('myFrame').contentWindow;

// 调用 iframe 中的方法
frameWindow.childMethod();

// 访问 iframe 中的变量
const childData = frameWindow.childVariable;

// 直接操作 iframe 的 DOM
const frameDoc = frameWindow.document;
frameDoc.getElementById('elementInFrame').style.color = 'red';

3. localstorage和监听storage

// 发送方
  localStorage.setItem('message', JSON.stringify({ data: 'Hello!' }));

  // 接收方
  window.addEventListener('storage', (event) => {
    if (event.key === 'message') {
      console.log('收到消息:', JSON.parse(event.newValue));
    }
  });

9. http和https

  1. 传输信息安全性不同
    • http协议:是超文本传输协议,信息是明文传输。数据在传输过程中可能被窃听、篡改
    • https协议:是具有安全性的ssl加密传输协议。确保数据传输的安全。
  2. 连接方式不同
    • http协议:http的连接很简单,是无状态的。
    • https协议:是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议。
  3. 端口不同
    • http协议:使用的端口是80。
    • https协议:使用的端口是443
  4. 证书申请方式不同
    • http协议:免费申请。
    • https协议:需要到ca申请证书,需要交费。

10. scss和less的区别

  1. 定义变量: scss:$color, less:@color
  2. 混合:
    • scss:使用 @mixin 定义,@include 调用
    • less:直接定义类,直接调用类
  3. 作用域:
    • scss块级作用域,如果想在局部修改全局变量需要 !global 标志可提升为全局变量
    • less全局作用域
  4. 选择建议:
    • scss需要复杂功能或者使用现代框架(Vue、React)
    • less简单轻量、适合简单项目和老项目
// scss使用 @mixin 定义,@include 调用
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  border-radius: $radius;
}
@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}
.button {
  @include border-radius(5px);
  @include flex-center;
}
scss:如果想在局部修改全局变量,需要使用 `!global`
$color: red;
.container {
  $color: blue !global; // 现在修改的是全局变量
  color: $color; // blue
}
.box {
  color: $color; // blue
}
LESS (延迟加载/全局作用域):
@color: red;
.box {
  color: @color; // 输出 blue!因为变量“延迟加载”,以后定义的为准
}
@color: blue; // 重新定义,覆盖之前的

10.SCSS 和 Sass 的区别

特性Sass(缩进语法)SCSS(CSS兼容语法)
文件扩展名.sass.scss
语法风格缩进式(无分号、无大括号)使用和CSS类似的大括号和分号
兼容性不兼容原生CSS完全兼容CSS
  1. 强大的变量系统 - 支持颜色、数值、字符串、列表、映射($primary-color)
  2. 嵌套结构 - 清晰的层次关系,减少重复代码
  3. 混合和继承 - 代码复用和模块化
//定义可复用的代码块:
@mixin flex-center { display: flex; justify-content: center; } 
.container { @include flex-center; }
//共享样式规则:
.alert { padding: 10px; } 
.error { @extend .alert; color: red; }

3. 丰富的函数 - 内置函数 + 自定义函数

@function darken($color, $amount) {
    @return darken($color, $amount); 
} 
.header { background: darken(blue, 10%); }

5. 逻辑控制 - 条件、循环等编程特性

@for $i from 1 through 3 { 
    .item-#{$i} { width: 100px * $i; } 
}

7. 模块化系统 - @use, @forward 管理依赖

11. vue组件通信方式

  1. 简单父子通信:Props、emit、通过ref直接访问组件暴露出的方法
  2. 兄弟组件通信:
    • 通过父组件中转数据
    • eventsbus:事件总线(任意组件间都能通信)
  3. 跨组件通信
    • provide / inject:祖先组件向后代注入数据
  4. 全局状态管理
    • vuex
    • pinia
  5. 其他:
    • localStorage/sessionStorage:通过浏览器存储通信(不是响应式的,可监听store的变化)
//------  eventsbus  ----------
  export const EventBus = new Vue()
  //发送事件
 EventBus.$emit('message-sent', {text: 'Hello from Component A'})
 mounted() {
 //接收事件
    EventBus.$on('message-sent', this.handleMessage)
  },
  beforeDestroy() {
  //销毁事件
    EventBus.$off('message-sent', this.handleMessage)
  },
  //-----  provide / inject  --------
  <!-- 祖先组件 -->
export default {
  provide() {
    return {
      appName: '我的应用',
      user: { name: '张三', role: 'admin' },
      reactiveData: this.reactiveData,// 提供响应式数据
      updateData: this.updateData// 提供方法
    }
  },
  data() {
    return {
      reactiveData: { version: '1.0.0' }
    }
  },
  methods: {
    updateData(newData) {
      this.reactiveData = { ...this.reactiveData, ...newData }
    }
  }
}
</script>
<!-- 后代组件(任意层级) -->
<script>
export default {
  inject: ['appName', 'user', 'reactiveData', 'updateData'],
  methods: {
    handleUpdate() {
      this.updateData({ version: '2.0.0' })
    }
  },
  mounted() {
    console.log('应用名称:', this.appName)
    console.log('用户信息:', this.user)
  }
}
</script>

//----------   localStorage/sessionStorage   -------------------
// 组件 A
 localStorage.setItem('shared-data', JSON.stringify(data))
// 组件 B
export default {
  mounted() {
    // 监听 storage 事件
    window.addEventListener('storage', this.handleStorageChange)
    // 直接读取数据
    const data = localStorage.getItem('shared-data')
  },
  beforeDestroy() {
    window.removeEventListener('storage', this.handleStorageChange)
  },
  methods: {
    handleStorageChange(event) {
      if (event.key === 'shared-data') {
        this.sharedData = JSON.parse(event.newValue)
      }
    }
  }
 }

12. vuex

  • Vuex是Vue.js应用程序开发的状态管理模式和库。它为Vue应用程序提供了一个集中式的存储机制,用于管理应用程序的所有组件的状态。
  • 作用: 组件间共享状态, 状态管理的可维护性, 跟踪状态变化.
  • state, getter, mutation(同步), action(异步), module
// Vuex 实现
const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    SET_COUNT(state, value) {
      state.count = value
    },
    INCREMENT(state) {
      state.count++
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('INCREMENT')
      }, 1000)
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2
  }
})

// 组件中使用
this.$store.commit('INCREMENT') //修改mutations
this.$store.dispatch('incrementAsync') //调用actions
this.$store.getters.doubleCount

13. vuex和pinia的区别

特性VuexPinia
状态定义statestate: () => ({})
计算属性gettersgetters
同步操作mutations❌ 无,直接修改
异步操作actionsactions
模块化modules + namespaced天然模块化
  • pinia:无mutations和modules(每个store都是独立的),同步和异步都在action中处理,更轻量1kb
import { defineStore } from 'pinia';
  export const useCounterStore = defineStore('counter', {
    state: () => ({ count: 0 }),
    getters: {
      doubleCount: (state) => state.count * 2,
    },
    actions: { // 同步和异步都在这里
      increment() {
        this.count++; // 直接修改,无需 commit
      },
      async incrementAsync() {
        setTimeout(() => {
          this.increment(); // 直接调用其他 action
        }, 1000);
      }
    }
  });
  // 在组件中使用
  import { useCounterStore } from '@/stores/counter';
  const counterStore = useCounterStore();
  counterStore.increment(); // 直接调用 action
  console.log(counterStore.doubleCount); // 直接访问 getter

14. vuerouter

15. vue插槽

  1. 默认插槽:父组件中放入子组件标签内的所有内容,都会在默认插槽的位置被渲染。
    • 子组件,
    • 父组件直接写内容这里是插槽内容
  2. 具名插槽:当一个组件需要多个插槽时,你可以给 <slot>元素添加一个 name属性。
    • 子组件,
    • 父组件<template #header>这里是插槽内容
  3. 作用域插槽:它允许子组件​​在插槽中向父组件传递数据​​,让父组件可以决定如何渲染这些数据。
<!-- 向父组件传递数据 -->
        <slot :item="item" :index="index"></slot>
     items: [
        { id: 1, name: '苹果', price: 5 },
        { id: 2, name: '香蕉', price: 3 },
        { id: 3, name: '橙子', price: 4 }
      ]
//父组件使用 - Vue 2
        <template>
          <child>
            <!-- 使用 `slotProps` 来接收所有传递过来的数据 -->
            <template v-slot:default="slotProps">
              <span class="item-name">{{ slotProps.item.name }}</span>
              <span class="item-price">¥{{ slotProps.item.price }}</span>
            </template>
          </child>
 //父组件使用 - Vue 3 语法
        <!-- 解构接收 -->
        <template #default="{ item, index }">
          <div class="item">
            <span>{{ index + 1 }}. {{ item.name }}</span>
            <span>¥{{ item.price }}</span>
          </div>

4. 动态插槽:插槽的名字也可以是动态的 * 子组件, * 父<template v-slot:[tab1]>

16. keep-alive

  • keep-alive 是 Vue 的内置组件,用于缓存不活跃的组件实例,而不是销毁它们。
  • 在没有 keep-alive 的情况下: 问题:  切换标签时,组件会不断销毁和重新创建,导致:
    • 状态丢失(表单输入、滚动位置等)
    • 重复的网络请求
    • 性能开销
  • 被 keep-alive 包裹的组件生命周期:
首次加载:
beforeCreate → created → beforeMount → mounted → activated
切换离开:
deactivated
再次进入:
activated
组件销毁:
deactivated → beforeDestroy → destroyed

17. vue2和vue3的区别

一、架构与性能优化
1. 响应式系统重写
  • 两者都是 Vue 的响应式系统核心,用于实现数据变化 → 视图更新的自动同步
  • Vue2的响应式系统基于Object.defineProperty,它通过劫持属性的getter和setter来实现响应式,但存在一些限制,比如无法检测属性添加、删除、遍历等操作,需要对数组进行特殊处理。
  • Vue3的Proxy则更强大,可以拦截整个对象,包括各种操作,提供了更好的性能和更全面的响应式支持。

截屏2025-10-04 下午4.36.58.png 截屏2025-10-04 下午4.35.59.png Vue 2:  使用 Object.defineProperty

// Vue 2 响应式原理
Object.defineProperty(obj, key, {
  get() { /* 依赖收集 */ },
  set(newVal) { /* 触发更新 */ }
});
  • 无法检测对象属性的添加/删除
  • 对数组的索引修改和长度修改无法追踪

Vue 3:  使用 Proxy

// Vue 3 响应式原理
new Proxy(obj, {
  get(target, key) { /* 依赖收集 */ },
  set(target, key, value) { /* 触发更新 */ }
});
  • 支持对象和数组的全量响应式
  • 性能更好,无需递归遍历对象
2. 体积更小
  • Vue 3 通过 Tree-shaking 优化,打包体积减少约 41%
  • 核心运行时体积从 ~20KB 减少到 ~10KB
二、语法
  • vue2使用选项式api, vue3使用组合式apiOptions API vs Composition API
  • Vue 3 - <script setup> 语法糖
三、组件相关变化
1.支持多根节点
  • Vue 2:  组件必须单个根元素
  • Vue 3:  支持多根节点
2.引入Teleport 组件

<Teleport> 组件的主要作用:

  1. 解决样式层叠问题 - 将组件移出可能影响其显示的父容器
  2. 管理 z-index 层级 - 确保重要组件在最上层显示
  3. 保持逻辑完整性 - 虽然 DOM 位置改变,但组件逻辑关系不变
  4. 提升用户体验 - 用于模态框、通知、下拉菜单等需要突破布局限制的组件
<template>
  <button @click="showModal">打开模态框</button>
  
  <Teleport to="body">
    <div v-if="isOpen" class="modal">
      <p>这个模态框会渲染到 body 标签下</p>
    </div>
  </Teleport>
</template>
四、v-if和v-for的优先级
在vue2中v-for的优先级高于v-if,可以放在一起使用,但是不建议这么做,会带来性能上的浪费
在vue3中v-if的优先级高于v-for,一起使用会报错。可以通过在外部添加一个标签,将v-for移到外层
五、生命周期变化
阶段Vue 2Vue 3 (Composition API)说明*
组件创建前、后beforeCreate createdsetup()组件创建前、后
挂载前beforeMountonBeforeMountDOM 挂载前
挂载后mountedonMountedDOM 挂载后
激活activatedonActivatedkeep-alive 特有
停用deactivatedonDeactivatedkeep-alive 特有
更新前beforeUpdateonBeforeUpdate数据更新前
更新后updatedonUpdated数据更新后
销毁前beforeDestroyonBeforeUnmount组件销毁前
销毁后destroyedonUnmounted组件销毁后
  1. activated 和 deactivated 只在被 keep-alive 包裹时有效
  2. 首次加载时mounted 和 activated 都会触发,顺序是 mounted → activated
  3. 后续切换时:只有 activated 和 deactivated 会触发,普通生命周期不会再次触发
18. 父子组件生命周期顺序
父组件 beforeCreate → created → beforeMount
→ 子组件开始创建:beforeCreate → created → beforeMount → mounted
→ 父组件 mounted

19. vue返回上一页执行的生命周期

1. 不使用 keep-alive(默认情况)
// 从 A 页面跳转到 B 页面
A 组件 beforeDestroy → destroyed
B 组件 beforeCreate → created → beforeMount → mounted

// 从 B 页面返回 A 页面
B 组件 beforeDestroy → destroyed

A 组件 ← 重新创建 beforeCreate → created → beforeMount → mounted 

2. 使用 keep-alive 缓存页面!
// 从 A 页面跳转到 B 页面
A 组件 deactivated      ← 只是停用,不是销毁!
B 组件 beforeCreate → created → beforeMount → mounted → activated

// 从 B 页面返回 A 页面
B 组件 deactivated
A 组件 activated        ← 重新激活,不会重新创建!

20. 宏任务、微任务

  • 微任务: Promise.then、MutationObserver、Node 中的 Process.nextTick等
  • 宏任务: script、setTimeout、setInterval、Node中的setImmediate、requestAnimationFrame 等 截屏2025-10-03 上午10.28.50.png 截屏2025-10-03 上午10.30.15.png

21. 浏览器输入url以后会发生什么

  1. 判断输入类型,如果是关键字,调用默认搜索引擎查询,如果是url,解析协议域名端口号
  2. DNS域名解析,浏览器缓存->系统缓存->路由器缓存->运营商DNS服务器缓存->根域名服务器逐级查询
  3. 建立TCP三次握手,发送->回复->确认回复
  4. 发送http请求,包含请求头请求体cookie
  5. 服务器处理响应并返回
  6. 浏览器渲染页面
  7. 断开连接 截屏2025-10-04 上午10.01.27.png 截屏2025-10-04 上午10.04.49.png

22. BFC

  1. 块级格式化上下文
  2. BFC原则: 如果一个元素具有BFC, 那么元素里边的内容不会影响外边的元素
  3. 如何触发:
  • float不为none
  • overflow不为visable
  • display值为: inline-block,table-cell
  • position值为: absolute, fixed 截屏2025-10-04 上午9.07.56.png 截屏2025-10-04 上午9.09.52.png
BFC作用:解决折叠问题、浮动元素高度塌陷问题

截屏2025-10-04 上午9.15.59.png

23.前端展示1w条数据

  1. 只渲染可视区域,监听浏览器滚动事件, 到底渲染下一步数据
  2. 时间分片,通过分批次插入DOM,使用requestAnimationFrame分批渲染,避免阻塞主线程,使用文档片段createDocumentFragment能够有效地减少重排和重绘,提高性能。
 1. 分批次渲染
    -   将10000个元素分成500批,每批20个
    -   避免一次性创建大量DOM导致的长时间阻塞
 2. requestAnimationFrame
    -   在浏览器下一次重绘前执行回调 
    -   将任务分割到不同的帧中执行 
    -   避免长时间占用主线程导致页面卡顿
 3. 文档片段(DocumentFragment)
        let fragement = document.createDocumentFragment();
        // 在内存中操作,不会触发重排重绘
        for(...) {
            fragement.appendChild(li);
        }
        // 一次性添加到DOM,只触发一次重排
        ul.appendChild(fragement);
const ul = document.getElementById('ul');  // 获取ul容器元素
const totalNum = 10000;  // 总共要创建10000个li
const onceNum = 20;      // 每次批量创建20个
const page = totalNum/onceNum;  // 计算总批次数(500次)
const index = 0;         // 起始索引
function loop(curTotal, curIndex) {
    if(curTotal <= 0) {  // 递归终止条件:没有剩余元素要创建
        return false;
    }
    const pageCount = Math.min(curTotal, onceNum);  // 本次要创建的数量
    window.requestAnimationFrame(() => {  // 在浏览器下一帧渲染时执行
        let fragement = document.createDocumentFragment();  // 创建文档片段
        for(let i = 0; i < pageCount; i++) {
            let li = document.createElement('li');
            li.innerText = curIndex + i + ':' + (Math.random() * totalNum);  // 创建li内容
            fragement.appendChild(li);  // 先添加到文档片段
        }
        ul.appendChild(fragement);  // 一次性将文档片段添加到DOM
        loop(curTotal - pageCount, curIndex + pageCount);  // 递归调用处理剩余元素
    })
}
loop(totalNum, index);  // 开始执行

24.大文件上传

"对于大文件上传,我采用切片上传 + 断点续传的方案:

  1. 前端将大文件切割成512KB的切片,使用Web Worker计算文件hash避免阻塞
  2. 上传前先校验,通过hash检查服务器已存在的切片,实现秒传和断点续传
  3. 控制并发上传,同时处理3-5个切片请求,平衡速度和服务器压力
  4. 所有切片上传完成后,通知后端合并文件
  5. 结合IndexedDB存储切片信息,支持刷新页面后继续上传
  6. 提供完整的进度反馈和错误恢复机制,提升用户体验

25.dom的diff算法

DOM Diff算法 + Key的作用:

// Diff算法:比较两棵DOM树的差异,最小化更新操作
// 目标:找到最少操作,从旧树变成新树

// 没有Diff算法的情况:
// 每次更新 → 销毁整个DOM → 重新创建整个DOM
// 性能极差,用户体验糟糕

// 有Diff算法的情况:
// 每次更新 → 比较差异 → 只更新变化的部分
// 高性能,保持用户交互状态
  1. 身份标识:Key帮助Diff算法识别哪些节点是相同的
  2. 高效复用:避免不必要的DOM销毁和重建
  3. 状态保持:确保组件状态在更新时正确保持
  4. 性能优化:减少DOM操作,提升渲染性能
vue2、vue3diff算法区别
  • Vue 2 的 diff 算法采用“双端比较”的策略,
    • 使用四个指针(旧头、旧尾、新头、新尾)同时从新旧子节点的两端向中间遍历
    • 如果两端交叉比较后都没有相同的,则尝试在旧节点中查找与 newStart 具有相同 key 的节点
  • Vue 3 的 diff 算法采用“最长递增子序列”的方法来最小化移动次数
    • 预处理:从两端开始进行同步,相同的跳过不参与对比,直到遇到第一个不同的节点。
    • Vue 3 的 diff 算法遍历新节点,通过寻找旧节点索引序列中的最长递增子序列,确定哪些节点不需要移动,来最小化 DOM 移动操作

26.import和require区别

import 是 ES6 模块规范,在编译阶段静态加载,在代码执行前就确定了模块依赖关系,支持 Tree Shaking(移除未引用代码)和代码分割,利于减小打包体积;仅能置于文件顶部,导入的值是浅拷贝,修改会同步影响源对象,
require 属于 CommonJS 规范,是运行时的函数调用,动态地加载并执行模块,不支持 Tree Shaking,需手动优化,可在代码任意位置,导入的值是深拷贝,修改不影响源对象,

27.git命令

回退命令

  1. 使用git reset(本地回滚,不保留提交记录 )
    • --hard:完全删除上次提交(包括代码改动)。
    • --soft:保留代码改动,仅撤销提交记录(修改会进入暂存区)。
    • HEAD~1表示“上一次提交”,HEAD~2表示“上两次提交”,以此类推
  2. 使用git revert(生成反向提交,保留历史记录)
    • git revert会创建一个新的提交,内容与上次提交相反(例如删除新增的代码)。
    • 适用于远程仓库已推送的情况,避免强制推送(git push --force)的风险。
   # 回滚到上一次提交之前(删除上次提交) 
   git reset --hard HEAD~1 
   # 如果只想撤销提交但保留代码修改(软回滚) 
   git reset --soft HEAD~1
   # 生成一个反向提交来撤销上次提交 
    git revert HEAD

经常使用的 git 命令?

   git init                     // 新建 git 代码库
    git add                      // 添加指定文件到暂存区
    git rm                       // 删除工作区文件,并且将这次删除放入暂存区
    git commit -m [message]      // 提交暂存区到仓库区
    git branch                   // 列出所有分支
    git checkout -b [branch]     // 新建一个分支,并切换到该分支
    git status                   // 显示有变更文件的状态
    `git reset --soft` 来回退但不丢弃之后的改动和提交。
    `git reset --hard` 来彻底丢弃之后的改动和提交。
    `git revert` 来创建一个新的提交以撤销之前的提交,同时保留历史记录。

28.Axios和promise的关系

  • Axios 是基于 Promise 封装的‌,它利用 Promise 的特性实现异步请求的链式调用和错误处理
  • 所有 Axios 请求返回 Promise
  • Axios 的 getpost 等方法默认返回一个 Promise 对象,因此可以直接使用 .then() 和 .catch() 处理响应或错误。
  • 也可以使用 async/await 语法,因为 async/await 是基于 Promise 的

29.js 冒泡和捕获方法区别

特性事件冒泡事件捕获
传播方向从里到外(子 → 父)从外到里(父 → 子)
默认行为默认启用(addEventListener参数为 false需显式启用(参数为 true
适用场景常用(如委托事件)常规事件处理特殊需求(如提前拦截)

事件循环面试题

1. 浏览器事件循环

截屏2025-10-03 上午10.33.24.png

* 2. 宏任务和微任务:

  • 微任务: Promise.then、MutationObserver、Node 中的 Process.nextTick等
  • 宏任务: script、setTimeout、setInterval、Node中的setImmediate、requestAnimationFrame 等 截屏2025-10-03 上午10.28.50.png 截屏2025-10-03 上午10.30.15.png

3. node事件循环,process.nextTick

node跟浏览器类似,都是v8引擎来处理js,事件循环是由libuv实现, 截屏2025-10-03 上午11.27.59.png

截屏2025-10-03 上午11.29.17.png 截屏2025-10-03 上午11.22.38.png

v8引擎

1. v8引擎执行原理

v8引擎是浏览器和node.js的处理js的引擎 截屏2025-10-03 上午11.38.14.png 截屏2025-10-03 上午11.39.31.png

2. js引擎(v8)常见的垃圾回收(GC)算法

截屏2025-10-04 下午2.54.39.png 截屏2025-10-04 下午2.56.27.png

this指向面试题

  • this指向跟定义位置没有关系,跟调用位置有关系,运行时才被绑定
  • 变量定义时就已经确定,跟定义位置有关系,跟调用位置没有关系

截屏2025-10-04 下午3.54.08.png 截屏2025-10-04 下午4.05.20.png 截屏2025-10-04 下午4.05.52.png 截屏2025-10-04 下午4.06.11.png 截屏2025-10-04 下午4.07.20.png

HTML-CSS面试题

1.什么事seo,为什么seo对一个网站很重要?

截屏2025-10-03 下午6.28.19.png

2.seo有哪些关键点,你在日常开发中,采取了哪些措施来进行seo?

截屏2025-10-03 下午6.40.18.png

截屏2025-10-03 下午6.40.41.png

截屏2025-10-03 下午7.10.05.png

截屏2025-10-03 下午7.11.52.png

3.defer和async属性在script标签中有什么作用

截屏2025-10-03 下午7.16.53.png

截屏2025-10-03 下午7.18.15.png

4.async、defer的面试回答

截屏2025-10-03 下午7.21.42.png

5.CSS3新特性

截屏2025-10-03 下午8.14.23.png

1. 选择器(Selectors):
  • 新的属性选择器

    • [attr^="value"]:选择属性值以 "value" 开头的元素。
    • [attr$="value"]:选择属性值以 "value" 结尾的元素。
    • [attr*="value"]:选择属性值中包含 "value" 的元素。
  • 结构性伪类

    • :nth-child(n):选择父元素下的第 n 个子元素。
    • :nth-last-child(n):选择父元素下的倒数第 n 个子元素。
    • :first-of-type:选择父元素下同类型中的第一个子元素。
    • :last-of-type:nth-of-type(n) 等。
2. 背景和边框(Backgrounds and Borders):
  • 边框图片border-image 属性,允许使用图像作为元素的边框。
  • 多重背景:允许一个元素设置多个背景图像,使用逗号分隔。
  • 圆角边框border-radius 属性,可以轻松创建圆角效果。
  • 盒阴影box-shadow 属性,为元素添加一个或多个阴影。
3. 文本效果(Text Effects):
  • 文本阴影text-shadow 属性,为文本添加阴影效果。
  • 文本溢出text-overflow 属性,定义当文本溢出包含元素时发生的事情(如显示 "...")。
  • 文字换行word-wrap 和 word-break 属性,允许对长单词进行换行。
4. 转换、过渡和动画:
  • 2D/3D 转换

    • transform 属性允许您对元素进行旋转 (rotate)、缩放 (scale)、倾斜 (skew) 或平移 (translate)。
    • 包括 3D 变换功能,如 rotateXrotateYtranslateZ 等。
  • 过渡transition 属性,允许 CSS 属性值在一定的时间区间内平滑地过渡。

  • 动画animation 属性和 @keyframes 规则,允许创建复杂的动画序列。

.transform-2d {
  transform: translate(100px, 50px); /* 移动 */
  transform: rotate(45deg); /* 旋转 */
  transform: scale(1.5); /* 缩放 */
  transform: skew(30deg, 20deg); /* 倾斜 */
  
  /* 多重变换 */
  transform: translateX(100px) rotate(45deg) scale(1.2);
}

transition: all 0.3s ease-in-out;
5. 其他重要特性(对您列表的补充):
  • 布局

    • Flexbox 布局display: flex,提供一种更有效的方式来布局、对齐和分配容器内项目之间的空间。
    • Grid 布局display: grid,创建基于网格的二维布局系统。
  • 颜色

    • RGBA 和 HSLA:支持 Alpha 通道(透明度)的颜色模式。
  • 盒模型

    • box-sizing 属性,可以改变计算元素宽度和高度的方式(如 border-box)。
  • 媒体查询@media,为不同屏幕尺寸和设备类型应用不同的样式,是响应式设计的核心。

6.为什么在移动端使用@2x、@3x的图片适配移动端

截屏2025-10-03 下午8.52.59.png

截屏2025-10-03 下午8.53.52.png

7.怎么画出0.5px边框

截屏2025-10-03 下午9.02.23.png

*****8.通常采用哪些措施保证网站或者应用在不同浏览器上的兼容性

截屏2025-10-04 上午9.22.29.png

浏览器渲染面试题

******1.浏览器输入url以后会发生什么?

2.浏览器内核是什么、有哪些常见浏览器内核?

截屏2025-10-04 上午10.09.30.png 截屏2025-10-04 上午10.10.29.png

******3.什么是回流、重绘

截屏2025-10-04 上午10.51.46.png

截屏2025-10-04 上午10.52.17.png

4.css文件如何被浏览器解析并应用到页面上

截屏2025-10-04 上午10.56.40.png

跨域访问面试题

****1.什么是同源策略,为什么浏览器会有同源策略

截屏2025-10-04 下午1.57.08.png

2.什么是正向代理、反向代理

正向代理

截屏2025-10-04 下午1.58.56.png

反向代理

截屏2025-10-04 下午1.59.37.png

*****3.描述开发中遇到的跨域问题,及解决方案

截屏2025-10-04 上午11.20.41.png

****4.如何使用nginx作为解决跨域的一种方法,他的工作原理

截屏2025-10-04 下午2.05.45.png

*****5.ngnix配置流程

截屏2025-10-04 下午2.08.19.png

异步编程方案相关面试题

1.Promise相关面试题

****promise是用来处理异步操作的对象

截屏2025-10-05 下午5.11.53.png

***Promise 的三种状态

// Promise 的三种状态
const promise = new Promise((resolve, reject) => {
  // pending(进行中)
  
  // 状态改变后不可逆:
  // resolve(value) → fulfilled(已成功)
  // reject(reason) → rejected(已失败)
});

Promise 的三种实例方法

// 使用 Promise
myPromise
  .then(result => {
    console.log('成功:', result);
  })
  .catch(error => {
    console.log('失败:', error);
  })
  .finally(() => {
    console.log('无论成功失败都会执行');
  });

****Promise 的静态方法

  1.  Promise.all() - 全部成功
Promise.all([promise1, promise2, promise3])
  .then(values => {
    console.log('所有都成功:', values); // [1, 2, 3]
  })
  .catch(error => {
    console.log('有一个失败:', error);
  });

2. Promise.allSettled() - 全部完成 截屏2025-10-05 下午5.23.54.png 截屏2025-10-05 下午5.25.01.png 3. Promise.race() - 竞速

截屏2025-10-05 下午5.27.31.png 4. Promise.any() - 任意一个成功 截屏2025-10-05 下午5.29.21.png

****2.async/await,与promise相比的优势和不同

async用于声明一个异步函数 await后面通常跟一个表达式,一般返回一个promise截屏2025-10-05 下午5.47.29.png

特性Promiseasync/await
代码风格链式调用,函数式同步风格,命令式
可读性复杂逻辑时嵌套深更接近同步代码,易于理解
错误处理.catch() 方法try/catch 块
async function async1 () {
  console.log('2---async1 start')
  await async2() // 这一句会同步执行,返回 Promise ,其中的 `console.log('async2')` 也会同步执行
  console.log('6---async1 end') // 上面有 await ,下面就变成了“异步”,类似 cakkback 的功能(微任务)
}
 
async function async2 () {
  console.log('3---async2')
}
 
console.log('1---script start')  
 
setTimeout(function () { // 异步,宏任务
  console.log('8---setTimeout')
}, 0)
 
async1()
// 初始化promise时,传入的函数会被立即执行
new Promise (function (resolve) { // 返回 Promise 之后,即同步执行完成,then 是异步代码
  console.log('4---promise1') // Promise 的函数体会立刻执行
  resolve()
}).then (function () { // 异步,微任务
  console.log('7---promise2')
})
 
console.log('5---script end')
 
// 同步代码执行完之后,屡一下现有的异步未执行的,按照顺序
// 1. async1 函数中 await 后面的内容 —— 微任务
// 2. setTimeout —— 宏任务
// 3. then —— 微任务
//初始化promise时,传入的函数会被立即执行,后面的then就是异步,为微任务

****ES6新特性面试题

ES6新特性面试题

webpack相关面试题

分包 SplitChunks webpack.optimize.CommonsChunkPlugin

前端构建速度优化

  1.使用高版本 Webpack 和 Nodejs
  2.多进程/多实例构建 thread-loader
  3.压缩代码
    多进程并行压缩
    webpack-paraller-uglify-plugin
    terser-webpack-plugin开发parallel
    mini-css-extract-plugin
  4.图片压缩
    imagemin
    image-webpack-plugin
  5.缩小打包作用域
  6.提取页面公共资源
    使用html-webpack-external-plugin 基础包通过cdn引入,不打入bundle中
    使用splitchunksplugin 提取公共脚本, 基础包 页面公共文件分离
  7.充分利用缓存,提升二次构建速度
    babel-loader
    terser-webpack-plugin
    cache-loader
  8.tree shaking
    删除没用的模块

webpack常见的loader

  raw-loader: 读取文件内容,返回字符串,不会转码。
  file-loader:
  url-loader: 读取文件内容,返回base64编码的字符串,不会转码。
  source-map-loader: 读取.map文件,返回源码。
  image-loader: 读取图片,返回base64编码的图片字符串,不会转码。
  json-loader: 读取JSON文件,返回JSON对象。
  babel-loader: 用babel转码代码。
  css-loader: 用来加载css文件。
  sass-loader: 用来加载SASS文件。
  ts-loader: 用来加载TypeScript文件。
  style-loader: 把css文件插入到html中
  postcss-loader: 用来处理css文件,支持css3新特性。
  eslint-loader: 用来检查代码中的语法错误。
  tslint-loader: 用来检查代码中的语法错误。
  vue-loader: 用来加载Vue文件。

webpack常用的plugin

  define-plugin: 用来定义环境变量。
  ignore-plugin: 用来忽略某些文件。
  html-webpack-plugin: 简化HTML文件创建。
  uglify-webpack-plugin: 用来压缩js。
  mini-css-extract-plugin: 用来提取css文件。
  clean-webpack-plugin: 用来清理构建目录。
  webpack-bundle-analyzer: 打包后打开一个页面可以查看文件大小。
  speed-measure-webpack-plugin: 用来查看构建时间。

Loader和Plugin的区别

1. Loader本质是一个函数,它可以对模块进行预处理,比如将ES6代码转换为ES5代码,
将SASS代码转换为CSS代码,将图片转换为base64编码的图片字符串,将JSON文件转换为JSON对象等等。
2. Plugin本质是一个类,它可以对构建过程进行扩展,比如添加新的功能,webpack运行生命周期中会广播很多实践,插件可以监听这些事件,并执行相应的操作。

3. loader:module.rules配置,类型是数组树,可以配置多个loader
4.  plugin:webpack.plugins配置,类型是数组树,可以配置多个plugin

webpack构建流程

  1.初始化参数:从配置文件和 shell 语句中读取并且合并参数,得到最终的参数
  2.开始编译:初始化Compiler 加载所有配置插件,执行象run 方法,开始编译
  3.确定入口:entry 找到所有入口
  4.编译模块:调用所有 loader 对模块进行翻译,找出模块依赖的模块,在递归本步骤知道所有入口依赖的文件都经过处理
  5.完成模块编译:得到每个模块被翻译后的最终内容以及他们之间的依赖关系
  6.输出资源:包含多个模块的 chunk,每个 chunk 转换成单独的文件加入到输出列表中,可以修改输出内容
  7.输出完成:根据配置确定输出的路径和文件名,把文件内容写出到文件系统

webpack高效率插件

  webpack-dashboard:更好的展示相关包的信息
  webpack-bundle-analyzer:打包后打开一个页面可以查看文件大小
  webpack-merge:合并webpack配置
  speed-measure-webpack-plugin:分析loader和plugin耗时,分析构建过程中的性能瓶颈
  HotModuleReplacementPlugin(HMR):模块热替换,当模块更新时,不会重新刷新页面,而是替换掉对应的模块,不会丢失状态。

xss攻击-跨站脚本攻击

  1. 危害:窃取cookie,劫持流浪,插入广告,植入木马,获取用户信息
  2. 攻击方式:url参数注入,输入框注入
  3. 分类:反射型(浏览器提交代码到服务器->服务端将代码传回客户端)、储存型(浏览器提交代码到服务器->将恶意代码储存到数据库)、DOM型(恶意代码仅在客户端执行)
  4. 预防:
校验(输入进行格式校验)、过滤(过滤特殊标签<script><iframe>,过滤onclick,onerror,onfocus等)、编码转义、限制(输入长度,cookie设置成httponly)
csrf 跨站请求伪造
  sec-fetch-site: same-origin
  攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
  攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
  整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
  跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。

两个特点:CSRF(通常)发生在第三方域名。CSRF攻击者不能获取到Cookie等信息,只是使用。  

性能优化面试题

截屏2025-10-10 上午9.56.02.png

1.项目架构

1.项目架构思路

截屏2025-10-10 上午9.59.22.png

截屏2025-10-10 上午10.45.12.png

2.项目架构实现一: 采用模块化的架构设计

截屏2025-10-10 上午11.45.05.png
截屏2025-10-10 上午11.48.03.png

3.项目架构实现一:其他方面的设计

截屏2025-10-10 上午11.54.02.png

2.项目开发:框架相关优化

截屏2025-10-10 下午12.05.10.png 截屏2025-10-10 下午12.05.38.png 截屏2025-10-10 下午12.06.01.png 截屏2025-10-10 下午12.06.55.png

3.项目部署:优化手段

截屏2025-10-10 下午3.04.55.png 截屏2025-10-10 下午3.17.14.png 截屏2025-10-10 下午3.20.22.png 截屏2025-10-10 下午3.22.19.png

要性能优化,需要从项目架构、项目开发、项目部署三个阶段来考虑。

(1)首先是项目架构方面。在正式开发之前,我们应该设计好整个项目的架构,目的是尽量对项目的模块进行解耦,方便多个程序员进行协同开发。解耦的标准可以按照功能或者状态划分。

例如我们的项目中,网络请求是最常使用的功能,所以相关的功能就划分成了单独的模块。在对Axios统一封装的时候,首先是基本的拦截和响应逻辑封装在一个文件中,有些配置项为了方便修改,我们会单独封装成另一个文件,例如自定义的状态码提示文字。然后为了方便阅读和维护,我们会把大的service.js文件拆分成一些处理不同功能的小service文件,比如userService、menuService等,用来划分不同的公共请求。至于每个具体的业务功能页面,我们会定制规范,规定用单独的文件夹包裹,每个页面自己的请求和封装成单独的js文件,和对应的vue代码放到一个文件夹中,确保文件结构清晰。

又例如项目中有一些通用的函数工具,我们会放在utils目录下。比如日期格式化、数字精度处理、嵌套对象展平、数组切割、权限校验等。这些函数不依赖外部状态,他们会在index.js中导出,供其他页面直接使用。

此外webpack、vite等工具也会对代码进行分割、动态导入还有tree shaking,这些都可以提升项目的性能。

还有git分支管理,每个人开发新需求的时候都从master分支拉一个新分支,合并的时候先往develop分支合并进行测试,没问题了再往release分支合并,在迭代结束时会有人专门把代码从release分支合并到master进行上线,然后下一个迭代开始时develop分支又会用master分支重置,这样可以大大减少代码合并的冲突。

项目的打包和部署用jenkins和rancher实现流程自动化,提升效率。

此外我们还会定期做code-review和文档整理,尽早发现并解决问题,减少问题的堆积。

(2)开发过程中的优化:

1. 避免组件不必要的渲染。具体手段包括:

①合理使用v-if和v-show;

②使用key确保组件唯一性,避免不必要的dom刷新;

③使用v-once确保不变的数据只渲染一次;

④合理使用生命周期钩子;

⑤使用import按需加载组件,减少初始加载时间;

⑥合理使用组件缓存动态组件,避免不必要的组件销毁和创建;

⑦有大量数据要渲染时,可以采用虚拟列表+无限滚动的方式来优化性能;

⑧尽量避免回流和重绘,尽量减少dom操作,使用批量更新。

2. 减少不必要的计算,尤其是避免在渲染过程中大量计算。应该把重计算的操作放在适当的位置,比如computed中,它可以缓存计算结果,避免重复计算。也可以放在web workers中,避免阻塞主线程,保持UI流畅。

3. 优化循环和迭代:比如获取数组长度arr.length在循环外边获取,避免在循环中创建新数组和对象;

4. 在频繁触发的事件上(点击、滚动)做好防抖和节流,减少事件处理频率

5. 避免内存泄漏,在组件中定时销毁计时器、事件监听器、闭包等

6. CSS相关优化:

①使用简单的CSS选择器,避免复杂的选择器链

②使用CSS动画,避免js动画

③使用transfrom和opacity处理动画效果,可以GPU加速

7. 图片优化,包括:

①提前用第三方工具对图片进行压缩处理;

②使用一些现代图片格式(webP、AVIF)来减小图片大小;

③使用精灵图,来降低网络开销;

④图片懒加载,只加载可视区域的图片,减少初始加载时间和网络消耗;

8. 服务端渲染(SSR),将完整的html发送到客户端,加快首屏渲染速度,也可以进行SEO优化

9. 使用webpack和vite对代码进行压缩、混淆和拆分(比如使用Terser等工具压缩js,使用其他工具压缩html和css)

10. 第三方包按需引入,例如elementplus等,使用babel或vite配置,按需引入,减少打包体积;

11. 状态下沉:根据虚拟dom的更新特性,将状态下沉到子组件,避免全局或父组件频繁更新

(3)部署过程中的优化:
  1. CDN的使用和配置,用于加速静态资源,将资源缓存在最近的服务器上

2.首屏加载速度优化,包括:

①将首屏渲染所需的关键CSS内联到html中,减少css阻塞渲染的时间;

②使用async和defer来异步加载JS脚本,避免阻塞渲染;

③懒加载、代码分割,将非关键的代码分离,减少初始加载时间;

④使用SSR技术(服务端渲染)

3.使用http缓存,在客户端缓存静态资源,避免重复请求设置http缓存头。为静态资源设置缓存策略,包括强缓存(需要cache-control和expires,一般缓存js、css文件,在文件更新时生成新的文件名,让客户端下载新的文件)和协商缓存(配置Etag和last-modified,一般用于频繁改变的文件,比如html文件)

  1. 压缩,包括:

①代码压缩(去掉多余的空格、空行、注释、代码缩短、tree-shaking,可以使用webpack、vite自带的压缩插件)

②图片压缩(一般用其他工具或者后端压缩,不在前端压缩,可以使用svg又小又无损缩放)、③文件压缩(在服务器配置中启用gzip就行,前端拿到.gzip文件会由浏览器自动解压)

1. 减少和优化资源请求:

①减少DNS查询,将多个资源放到同一个域名下,减少DNS查询时间;

②通过异步加载或延迟加载(例如async和defer)减少第三方脚本的影响。

③必须跨域的资源可以用DNS预加载和预解析:

预加载(preload,例如 来预加载关键资源)和预解析(prefetch,例如 来预获取将来可能用到的资源)

 

4. 性能测量工具(待续):

1.performance

performance,浏览器自带提供,给各种性能做测量工作,performance.now()可高精度时间测量,以毫秒为单位,精确到小数点后五位(微妙),还可以用performance.mark和performance.measure等

截屏2025-10-10 下午3.23.40.png

页面加载时间测量

截屏2025-10-10 下午3.24.25.png 截屏2025-10-10 下午3.25.13.png

截屏2025-10-10 下午3.25.39.png

先用lightHousec查看当前页加载性能,时间性能,明显感觉那个页面卡用Performance检测哪里有问题,如果大可以拆开不行就分包处理

2.谷歌工具:Performance(性能面板)

"Performance 工具是我们分析运行时性能的首选。比如当用户反馈页面操作卡顿时,我会用 Performance 录制一段操作,重点分析:

  • Long Tasks:查找执行时间超过 50ms 的长任务
  • Layout Thrashing:检查是否存在频繁的强制同步布局
  • Main Thread Bottlenecks:定位 JavaScript 执行或渲染的瓶颈

核心功能

  • 帧率分析:检查是否保持 60fps 流畅度
  • 主线程活动:查看 JavaScript 执行、布局、绘制等耗时
  • 网络请求时间线:结合资源加载分析性能瓶颈
3.谷歌的light-house工具

核心指标(Core Web Vitals):

  • LCP(最大内容绘制):加载性能
  • FID(首次输入延迟):交互响应性
  • CLS(累积布局偏移):视觉稳定性

面试回答示例:

"Lighthouse 是我们持续监控网站健康度的标准工具。在项目中我们把它集成到 CI/CD 流程中,每次发布前自动检测:

  • 性能评分:确保不低于 90 分
  • 核心 Web 指标:监控 LCP、FID、CLS 是否达标
  • 最佳实践:检查 HTTPS、图片优化等

通过 Lighthouse 的报告,我们系统性地优化了图片懒加载、资源压缩等,让首屏加载时间从 4s 降到 1.8s。"

4.谷歌工具:nextWork

监控所有网络请求的详细信息的工具。

核心分析维度

  • 请求瀑布流:分析请求依赖和并行性
  • 资源大小:检查未压缩的资源
  • 请求优先级:验证关键请求是否被优先处理

面试回答示例

"Network 面板是我优化加载性能的基础工具。主要关注:

  • 关键请求链:找出阻塞渲染的核心资源
  • 资源压缩:检查图片、JS、CSS 是否合理压缩
  • 缓存策略:验证静态资源缓存配置是否正确

曾经发现一个 2MB 的未压缩图片,优化后体积减少 80%,显著改善了 LCP 指标。"

分层诊断思路:

"我习惯按加载性能 → 运行时性能 → 综合质量的层次使用不同工具:

  1. 首先用 Network + Lighthouse 诊断加载阶段问题

    • Network 看具体请求细节
    • Lighthouse 看整体评分和核心指标
  2. 然后用 Performance 分析运行时交互性能

    • 录制用户操作,分析长任务和渲染瓶颈
  3. 最后用 Light-house 验收 整体优化效果

    • 确保各项指标达到标准"
      截屏2025-10-10 下午4.04.54.png 截屏2025-10-10 下午4.05.27.png 截屏2025-10-10 下午4.03.18.png

webpack\git相关

xxx1.整理npm、yarn常用的命令以及作用
    | npm                              | yarn                         | 描述                           |
| :------------------------------- | ---------------------------- | ------------------------------ |
| npm install                      | yarn  install                | 根据package.json中的依赖包安装 |
| npm install [package]            | yarn add [package]           | 默认安装开发和生产依赖         |
| npm install --save [package]     | yarn add [package]           | 默认安装开发和生产依赖         |
| npm install --save-dev [package] | yarn add [package][--dev/-D] | 安装开发依赖                   |
| npm rebuild                      | yarn install --force         | 强制重新build                  |
| npm uninstall [package]          | yarn remove [package]        | 卸载某个依赖包                 |
| npm cache clean                  | yarn cache clean             | 清除缓存                       |
| npm update [package]             | yarn upgrade                 | 更新指定包                     |
xxx2.说出npm install的安装过程

b361a3e3-89aa-4738-82cc-eacc2a5e5764.png

xxx3.npm、cnpm、yarn、pnpm
  • yarn b17ff019-a7e7-4a00-bd15-5ff3b71b8700.png
  • cnpm:设置镜像 1ccd7507-3358-4239-bb22-40e007f3ad05.png
  • pnpm:更高效的包管理工具

xxx4.说说pnpm的原理(软连接、硬链接)和用法

  • 软链接(符号链接)
    • 保存某个文件的绝对路径或者相对路径
    • 类似于快捷方式
  • 硬链接
    • 是电脑文件系统中的多个文件平等地共享同一个文件存储单元
    • 删除一个文件名字后,还可以用其它名字继续访问该文件

4e362d35-8834-4305-b742-1c5437299da8.png

  • pnpm的node_modules是非扁平化的结构
    • 让自己的项目不会随便引入非自己安装的依赖
    • 软连接和硬链接结合:node_modules下文件是软连接、指向node_modules下的.pnpm文件中的硬链接,这些硬链接指向测盘中存放的真正的包
  • pnpm的使用
    | npm命令             | pnpm等价命令      | 描述                       |
| ------------------- | ----------------- | -------------------------- |
| npm install         | pnpm install      | 安装package.json中的依赖包 |
| npm install <pcg>   | pnpm add <pcg>    | 默认安装开发和生产依赖     |
| npm uninstall <pcg> | pnpm remove <pcg> | 卸载某个依赖包             |
| npm run <cmd>       | pnpm <cmd>        | 运行某个脚本               |
xxx5.什么是webpack

85b785ea-33a9-437b-b0c9-2b8f8ad7e4a3.png

***6.webpack如何对项目进行打包

5c8442a2-4427-4c02-850c-6cccb65618b8.png - 最终会生成可部署的静态资源文件

***7.什么是loader?webpack的loader是什么作用?

什么是loader?
  • loader用来对模块的源代码进行转换,加载文件
    • 比如因为webpack 不知道怎么样去加载css文件,所以我们需要用css-loader来加载css文件
    • 主要通过配置方式来使用loader来加载,在webpack的配置文件的module.rules
    • 处理流程:webpack遇到文件→匹配rules规则→使用指定loader处理→输出结果
     module: {
        rules: [
          {
            // 告诉webpack匹配以.css结尾的文件
            test: /\.css$/,
            // use: [
            //   // 注意顺序,从下往上执行
            //   { loader: "style-loader" },
            //   { loader: "css-loader" }
            // ]
            //简写一: 如果loader只有一个
            // loader: "css-loader"
            //简写二: 多个loader不需要其他属性时,可以直接写loader字符串形式
            // 配置方式一
            use: ["style-loader", "css-loader", "postcss-loader"]
            // 配置方式二
            // use: ["style-loader", "css-loader", {
            //   loader: "postcss-loader",
            //   options: {
            //     postcssOptions: {
            //       plugins: [
            //         "autoprefixer"
            //       ]
            //     }
            //   }
            // }]
          },
          {
            // 告诉webpack匹配以.css结尾的文件
            test: /\.less$/,
            // use: [
            //   // 注意顺序,从下往上执行
            //   { loader: "style-loader" },
            //   { loader: "css-loader" },
            //   { loader: "less-loader" },
            //   { loader: "postcss-loader" }
            // ]
            // 简写
            use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
          }
        ]
      }

***8. loader和plugin的区别

  • loader是用于特定的模块类型(css,vue...)进行解析加载
  • plugin 是用于执行更多广泛的任务,比如打包优化,资源管理,环境变量注入等

核心区别:

  • Loader作用:用于特定模块类型的转换,进行加载,进行解析时用,如处理.vue、.css、.png等确定类型的文件, 仅在文件加载转换阶段执行

  • Plugin作用:执行更广泛的任务,包括打包优化、资源管理、环境变量注入等 (执行loader外所有任务,并且贯穿整个生命周期)

  • loader:module.rules配置,类型是数组树,可以配置多个loader

  • plugin:webpack.plugins配置,类型是数组树,可以配置多个plugin

9.常见的loader和plugin

    vue-loader: 用来加载Vue文件。
    
    postcss-loader: 用来处理css文件,自动添加浏览器前缀,支持css3新特性。 
    less-loader: 将less编译为css
    sass-loader: 用来解析SASS文件。
    css-loader: 用来解析css文件。
    style-loader: 将css注入到DOM中 
    
    babel-loader: webpack遇到.js文件时,会先用babel-loader进行转译,将ES6+代码(如箭头函数、class)转换为ES5等更兼容的语法
    ts-loader: 用来解析TypeScript文件。 
    eslint-loader: 用来检查代码中的语法错误。 
    tslint-loader: 用来检查代码中的语法错误。
    
    json-loader: 读取JSON文件,返回JSON对象。
    image-loader: 读取图片,返回base64编码的图片字符串,不会转码。
    file-loader: url-loader: 读取文件内容,返回base64编码的字符串,不会转码。
    raw-loader: 读取文件内容,返回字符串,不会转码。 
    source-map-loader: 读取.map文件,返回源码。 
   VueLoaderPlugin:处理.vue单文件组件
   CleanWebpackPlugin:清理构建目录:每次修改了一些配置,重新打包时,帮助我们删除dist文件夹
   HtmlWebpackPlugin:对index.html进行打包处理,自动在dist文件夹中,生成了一个index.html的文件
   DefinePlugin:定义全局常量,是一个webpack内置的插件(不需要单独安装)
   -    比如process.env.NODE_ENV:判断当前环境是开发还是生产
    
   mini-css-extract-plugin: 将CSS提取到单独的文件中。它支持按需加载CSS和源映射 
   webpack-bundle-size-analyzer: 分析包的大小。
   speed-measure-plugin: 测量webpack构建速度。
10.webpack的开发模式和生产模式有什么区别?
  • Mode: development 开发模式
    • 会将process.env.NODE_ENV 的值设置为development
  • Mode: production 生产模式
    • 会将process.env.NODE_ENV 的值设置为production

***11.什么是babel?babel在开发中是什么作用?

  • Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript (ES6以上的代码转成ES5代码)
  • 作用: 语法转换,源代码转换,箭头函数转换 ,ES6以上的代码转成ES5代码

12.总结整理git常见的命令, 并且说明在什么场景会用到这个命令

04f06691-29e4-4ca7-984b-b3d52bf048b8.png git文件大致分为四种状态

  • Untracked 未跟踪的文件
    • 没有通过git追踪的文件
    • 使用git add 使得该文件被追踪
  • Unmodified 未修改的
    • 已被git记录 但是还没有被修改(比如新创建的文件)
  • Modified 已修改的
    • 已经进行修改的文件 但是暂时没有进行缓存
  • Staged 暂缓区中的文件状态
    • 已经提交到git本地缓存中的文件
    • 提交缓存之前需要将文件添加到暂存区 git add .
    • 之后进行 git commit -m "提交信息"将文件提交到缓存中
    • 简写 git commit -a -m ""