滴滴前端面试总结

滴滴前端开发面试总结

面试题目

1、js中的单线程和事件循环,宏任务和微任务

2、Js实现继承有哪几种方式?

3、Js 中apply(),call()和bind()的区别

4、从输入url到渲染页面

5、js 中的闭包及其使用场景

6、介绍一下Promise的状态及其方法

7、介绍一下async/await 的实现原理

8、箭头函数和普通函数有什么区别

9、什么是BFC?

10、什么是Css中的回流(重排)与重绘?

11、Css中移动端适配有哪些方案?

12、常用的跨域解决方案有哪些?

13、Vue2与Vue3中的双向数据绑定

14、Vue中template模版的编译原理

15、Vue2中的diff流程

16、Vue3中的diff流程

17、Vue中的组件间通信有哪些?

18、Vue-router中如何实现懒加载?

19、Vue3相对于Vue2进行了哪些优化?

20、React有哪些常用的hooks?

21、介绍下React中的useEffect

22、React中常用的高阶组件有哪些?

23、介绍一下React Fiber

24、React Hook为什么不能放到条件语句中?

25、Webpack中有哪些核心概念?

26、Vite 和 Webpack 的区别

27、Webpack常见的优化方案有哪些?

28、浏览器中强缓存与协商缓存的缓存机制

面试详解

1、js中的单线程和事件循环,宏任务和微任务

JS是单线程的,同一时间只能执行一个任务,如果执行的任务需要等待一段时间才能完成,那么就会导致程序阻塞,影响用户体验。

JavaScript 事件循环是一种执行模型,用于处理代码执行过程中的异步操作和回调函数。它负责管理 JavaScript 代码的执行顺序,使得异步操作能够以非阻塞的方式进行。

事件循环由一个主线程和一个任务队列组成。当 JavaScript 执行代码时,同步任务会立即执行,而遇到异步任务时,它们会被放入任务队列中等待执行。当主线程空闲时,事件循环会从任务队列中取出一个任务并执行。这个过程不断重复,即事件循环的运行机制。

宏任务(macrotask): setTimeout、setInterval、I/O 操作、事件等。

微任务(microtask): Promise 的回调函数、MutationObserver、Object.observe 等。

一般情况下,微任务会优先于宏任务执行。

当 JavaScript 执行到某个宏任务时,会先执行当前任务中的所有微任务,然后再执行下一个宏任务。换句话说,微任务会在当前宏任务执行完毕之前被处理。

2、Js实现继承有哪几种方式?

  1. 原型链继承:将父类的实例作为子类的原型,通过 prototype 进行继承
  2. 构造继承:将父类的实例属性复制给子类,通过 call 进行继承
  3. 实例继承:为父类实例添加新特性,作为子类实例返回
  4. 拷贝继承:将父类实例通过循环拷贝给子类
  5. 组合继承:就是 原型链继承 和 构造继承,一起使用
  6. 寄生组合继承:通过寄生方式,砍掉父类的实例属性,避免了 组合继承中,在调用两次父类的构造时,初始化两次实例方法/属性 的缺点

3、Js 中apply(),call()和bind()的区别

都可以用来改变函数内部的 this 指向

  • call() 和 apply() 是立即调用函数,并改变函数的执行上下文。
  • call() 的参数是逐个传入,而 apply() 的参数是以数组形式传入。
  • bind() 创建一个新函数,不会立即执行,可以稍后调用。

4、从输入url到渲染页面

  1. 户在浏览器中输入 URL 地址或点击链接,触发请求的发送
  2. DNS 解析:浏览器会解析 URL 中的域名部分,以获取对应的 IP 地址。
  3. 建立 TCP 连接:浏览器通过 TCP 协议与服务器建立连接
  4. 发送 HTTP 请求:浏览器根据用户请求的方法(GET、POST 等)和请求头信息构建 HTTP 请求报文。
  5. 服务器处理请求:服务器接收到请求后,根据请求的 URL 和参数等进行处理。
  6. 服务器发送 HTTP 响应:服务器生成 HTTP 响应报文,发送回客户端
  7. 客户端接收响应:浏览器接收到服务器发送的 HTTP 响应报文。
  8. 浏览器渲染页面:如果响应的内容是 HTML 页面,浏览器会解析 HTML,并构建 DOM 树。同时,浏览器还会解析 CSS 样式和 JavaScript 脚本,并进行相应的处理。最终,浏览器将解析后的内容渲染成可视化的页面。

5、js 中的闭包及其使用场景

闭包是指在一个函数内部定义的另一个函数,这个内部函数可以访问到其外部函数中的变量和参数,即使外部函数已经执行完毕并返回了,内部函数仍然可以保留对这些变量和参数的引用,形成了一个“闭合”的作用域,因此称为闭包。

简单的来说:闭包是指有权访问另外一个函数作用域中的变量的函数

应用场景:

  • 保护变量:可以用闭包来保护变量不被意外修改。
  • 封装私有变量和方法
  • 延迟执行:可以实现防抖节流

6、介绍一下Promise的状态及其方法

Promise 是异步编程的一种解决方案

promise有三种状态:pending(等待态),fulfiled(成功态),rejected(失败态);状态一旦改变,就不会再变。

  • then(onFulfilled, onRejected):用于指定当异步操作成功时(Fulfilled 状态)和失败时(Rejected 状态)所执行的回调函数。可以通过链式调用多个 then 方法来处理异步操作的结果。
  • catch(onRejected):用于指定当异步操作失败时(Rejected 状态)所执行的回调函数。通常用于捕获异常情况。
  • finally(onFinally):无论 Promise 对象最终状态如何(Fulfilled 或 Rejected),都会执行指定的回调函数。通常用于无论成功还是失败都需要执行一些清理工作。
  • Promise.all(iterable):接收一个可迭代对象(比如数组),当所有 Promise 对象都变为 Fulfilled 或其中之一变为 Rejected 后,返回一个新的 Promise 对象。结果是包含多个异步任务结果的数组
  • Promise.race(iterable):接收一个可迭代对象,返回一个 Promise 对象,一旦迭代器中的某个 Promise 对象变为 Fulfilled 或 Rejected,返回的 Promise 对象就会采用这个 Promise 的状态和值。

7、介绍一下async/await 的实现原理

async/await 是一种处理异步操作的语法糖,它让异步代码看起来更像同步代码,更易于理解和编写。实现原理:

  • 在底层,async/await 实际上是基于 Promise 实现的。
  • 当遇到 await 关键字时,JavaScript 引擎会暂停当前 async 函数的执行,并注册一个微任务(microtask)。
  • 等待 await 后的 Promise 对象状态变化后,微任务队列中的任务会被执行,继续执行 async 函数后面的代码。
  • 在实际执行时,async/await 可以理解为 Generator 函数和 Promise 的结合,通过 Generator 的暂停和恢复特性,实现了暂停和继续执行异步操作的能力。

8、箭头函数和普通函数有什么区别

  • 写法不同:箭头函数使用箭头(=>)来定义,而普通函数使用 function 关键字定义
  • this 的处理方式不同:在箭头函数中,this 的值与外层作用域的 this 绑定。而在普通函数中,this 的值由调用该函数的方式决定。
  • 箭头函数没有 arguments 对象:箭头函数中没有自己的 arguments 对象,它的参数只能通过参数列表来传递。
  • 箭头函数不能用作构造函数:由于箭头函数中没有自己的 this 值,因此不能用作构造函数来创建对象实例。

9、什么是BFC?

BFC(块级格式化上下文)它是页面中一个独立的渲染区域,拥有自己的布局规则。BFC具有一些特性,例如浮动元素不会覆盖BFC区域,BFC可以包含浮动元素,BFC可以阻止垂直外边距重叠等。

有几种方式可以触发一个元素的BFC,实现方法如下:

  1. 设置浮动(float):将元素设置为浮动,例如将其float属性设置为left或right,这会触发元素的BFC。
  2. 设置定位(position):将元素的position属性设置为absolute或fixed
  3. 设置overflow属性:将元素的overflow属性设置为非visible的值,如auto、hidden、scroll
  4. 设置display属性为inline-block、table-cell、table-caption或inline-flex
  5. 使用块级格式化上下文的根元素:HTML文档中的根元素(通常是html或body元素)本身就是一个BFC。

10、什么是css中的回流(重排)与重绘?

回流指的是当页面的布局和几何属性发生变化时,浏览器会重新计算元素的位置和大小,然后更新页面的布局。回流会影响到整个页面的渲染,并且比较消耗性能。常见引起回流的操作包括改变窗口大小、修改元素的尺寸、添加或删除元素等。

重绘指的是当页面的外观属性(如颜色、背景等)发生变化时,浏览器会重新绘制受影响的部分,但不会重新计算位置和大小。重绘的开销比回流小很多,因为它只需要重新绘制元素的外观,而不需要重新计算布局。

11、css中移动端适配有哪些方案?

  • 媒体查询(Media Queries)
  • rem布局:rem是指相对于根元素(html)字体大小的单位,可以根据根元素的字体大小来确定其他元素的大小
  • vw/vh布局:vw/vh是指相对于视口宽度/高度的单位,可以根据视口的大小来确定元素的大小。

12、常用的跨域解决方案有哪些?

跨域:浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。

  • CORS: 全称是跨域资源共享,是一种 ajax 跨域请求资源的方式,支持现代浏览器,支持IE10以上。当你使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin(访问控制允许来源); 浏览器判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
  • JSOP: JSONP是通过script 标签加载数据的方式去获取数据当做 JS代码来执行 提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上「包裹」这个函数名,发送给前端。换句话说,JSONP需要对应接口的后端的配合才能实现。
  • Proxy:在前端应用内部建立一个代理服务器,将请求发送到该服务器上,再由该服务器转发请求到后端,最后将响应结果返回给前端。虽然代理可以解决跨域问题,但是会增加服务器负担,因此需要合理使用。

13、Vue2与Vue3中的双向数据绑定

当数据传入vue的实例中作为data数据时,vue将遍历此对象的所有property,并且使用Object.defineProperty把他们转化为getter和setter方法,而get和set正是对属性的读写进行监控

Vue 2.x能够监听数据对象的变化,但是监听不到对象属性的增删、数组元素和长度的变化;Vue 3.x 采用了 Proxy 换掉了 Vue 2.x 中的 Object.defineProperty 实现双向绑定

14、Vue中template模版的编译原理

Vue 中的模板编译原理可以简单概括为将模板字符串转换成渲染函数(render function),这个过程涉及到以下几个步骤:

  1. 解析模板:Vue 编译器会先对模板进行解析,将模板字符串转换成抽象语法树(AST)的形式。
  2. 静态分析:在静态分析阶段,Vue 会识别模板中的指令、插值表达式、事件处理等,并建立相应的 AST 节点。
  3. 优化:Vue 会对生成的 AST 进行优化,包括静态节点提升、标记静态根节点等优化操作,以提高渲染性能。
  4. 生成渲染函数:最终,Vue 将优化后的 AST 转换成渲染函数,这个渲染函数接收一个 createElement 函数作为参数,用于创建 VNode(虚拟 DOM 节点)。
  5. 执行渲染函数:当组件需要渲染时,会执行生成的渲染函数,通过 createElement 创建 VNode,并最终渲染成真实的 DOM 元素。

总的来说,Vue 的模板编译原理将模板字符串转换成渲染函数,通过渲染函数的执行来生成虚拟 DOM,并最终更新到真实的 DOM 上,实现数据驱动视图的更新。这个过程大大简化了开发者编写组件的工作,同时也提高了 Vue 应用的性能和效率。

15、Vue2中的diff流程

在更新视图时,通过比较新旧虚拟 DOM 树的差异,找出最小的变更,并将这些变更应用到实际的 DOM 中,以实现视图的高效更新

  1. 生成新的虚拟 DOM 树:当数据发生变化时,Vue 会重新渲染组件,生成新的虚拟 DOM 树。
  2. 比较新旧虚拟 DOM 树:Vue 会将新的虚拟 DOM 树和旧的虚拟 DOM 树进行比较,找出两者之间的差异。
  3. Diff 算法:Vue 使用了一种基于深度优先搜索的算法来进行 Virtual DOM 的差异比较。在比较过程中,Vue 会尽量复用已存在的节点,减少对实际 DOM 的操作,从而提高性能。
  4. 生成变更记录:在比较过程中,Vue 会生成一份变更记录,记录需要对实际 DOM 进行的操作,包括插入、移动、更新和删除等操作。
  5. 应用变更:最后,Vue 会根据变更记录逐条对实际 DOM 进行操作,将变更应用到实际 DOM 上,完成视图的更新。

16、Vue3中的diff流程

Vue 3 中的 diff 流程与 Vue 2 中有所不同,主要是因为 Vue 3 引入了新的响应式系统和编译器优化。

  1. 编译器优化:在编译期间,Vue 3 的编译器会对模板进行静态分析,并将静态节点提取出来,生成标记静态根节点的渲染函数。这样可以减少渲染函数的生成和执行次数,提高渲染性能。
  2. 响应式更新:当数据发生变化时,Vue 3 的响应式系统会立即触发组件的重新渲染。
  3. 生成新的虚拟 DOM 树:重新渲染组件时,Vue 3 会生成新的虚拟 DOM 树。
  4. 比较新旧虚拟 DOM 树:Vue 3 会将新的虚拟 DOM 树和旧的虚拟 DOM 树进行比较,找出两者之间的差异。
  5. Diff 算法:Vue 3 中使用了一种名为“递归分裂算法”的 diff 算法,它通过将新旧节点的子节点按照一定规则分成多个小区间,然后进行比较和更新,从而减少了无意义的比较,提高了 diff 的效率。
  6. 生成变更记录:在比较过程中,Vue 3 会生成一份变更记录,记录需要对实际 DOM 进行的操作,包括插入、移动、更新和删除等操作。
  7. 应用变更:最后,Vue 3 会根据变更记录逐条对实际 DOM 进行操作,将变更应用到实际 DOM 上,完成视图的更新。

Vue 3 中的 Virtual DOM diff 流程借助编译器优化和新的递归分裂算法,提高了渲染性能和效率,同时保证了视图的正确性。这个过程减少了无意义的比较,提高了 diff 的效率,从而实现了性能优化和视图的高效更新。

17、Vue中的组件间通信有哪些?

Vue 组件间通信有以下几种方式:

  • 父子组件通信:父组件通过props将数据传递给子组件,子组件通过$emit触发自定义事件回传数据
  • 子父组件通信:子组件通过this.parent访问父组件实例,或通过emit触发自定义事件回传数据
  • 兄弟组件通信:通过一个事件总线(Event Bus)或者Vuex来实现,Event Bus 就是通过一个新的 Vue 实例来实现数据传输
  • 跨级组件通信:通过provide/inject来实现,provide可以在祖先级别中注册一个变量,inject可以在子孙级别中注入

18、Vue-router中如何实现懒加载?

在路由配置文件中使用动态导入import()语句,并用箭头函数返回实现路由懒加载。

const routes = [  {    path: '/home',    name: 'Home',    component: () => import('./views/Home.vue')  },  {    path: '/about',    name: 'About',    component: () => import('./views/About.vue')  }];const router = new VueRouter({  routes});

19、Vue3相对于Vue2进行了哪些优化?

  • Vue 3 引入了 Composition API,这是一种基于函数的 API 风格,使得代码组织更加灵活和可复用。相比于 Vue 2 的 Options API,Composition API 更适合大型项目和复杂组件的开发。
  • 性能优化:Vue 3 在编译器、响应式系统和虚拟 DOM 等方面进行了优化,提高了整体性能。具体来说,Vue 3 引入了编译器优化、树懒执行、静态提升、模块化的运行时,以及更快的虚拟 DOM 渲染等功能,从而使应用程序更加高效。
  • 更灵活的响应式系统:Vue 2.x 中响应式系统的核心是 Object.defineProperty,劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,实现响应式。Vue 3.x 中使用 Proxy对象重写响应式系统。
  • 更快的渲染速度:Vue3 的编译器生成的渲染函数比 Vue2 生成的更高效。
  • 编译阶段:Vue 2.x 通过标记静态节点,优化 diff 的过程。Vue 3.x中标记和提升所有的静态节点,diff的时候只需要对比动态节点内容。
  • 更小的体积:Vue3 将源码拆分为多个独立的模块,这样就可以按需导入所需的模块,从而减小了整个库的体积。
  • 更好的 TypeScript 支持:Vue3 对 TypeScript 的支持更加友好,内部使用了更先进的 TypeScript 特性,并为其提供了更好的声明文件。
  • 更好的组件系统:比如,Vue3中引入了一个新的 Fragment 组件,它可以替代原来的 template 标签作为根节点

20、React有哪些常用的hooks?

  • useState:通过 useState,可以创建一个状态变量及其更新函数,并在组件内使用该变量来保存和更新组件的状态。
  • useEffect:用于在组件渲染完成后执行一些副作用操作(例如订阅数据、更新 DOM 等)。通过 useEffect,可以在组件加载、更新和卸载时设置和清理副作用操作,并且可以在副作用操作之间共享状态。
  • useContext:用于在组件之间共享一些全局的状态或函数,以避免通过多层嵌套的 Props 传递进行数据传输。通过 useContext,可以让组件在全局状态或函数的上下文中运行,并让它们能够方便地读取或更新全局状态或函数。
  • useReducer:通过 useReducer,可以创建一个状态容器及其更新函数,并在组件内使用该容器来保存和更新组件的状态。
  • useMemo:用于在组件渲染完成后缓存一些计算结果,以避免因为重复计算导致的性能问题。通过 useMemo,可以创建一个缓存变量,并在组件内使用该变量来保存计算结果并缓存。
  • useCallback:用于在组件渲染完成后,将一些函数进行缓存,以避免因函数重复创建导致的性能问题。通过 useCallback,可以创建一个缓存函数,并在组件内使用该函数来代替重复创建的函数。
  • useRef:用于在组件渲染完成后创建一个引用,以便在组件多次渲染时能够保留上一次渲染中的值。通过 useRef,可以创建一个引用变量,并在组件内使用该变量来保存一些持久化的数据。
  • useImperativeHandle:用于在组件中实现一些自定义的 Ref 对象,并且要求将一些组件内部的方法或状态暴露给父组件使用。通过 useImperativeHandle,可以创建一个自定义的 Ref 对象,并在组件内指定一些公开的方法或属性。
  • useLayoutEffect:该 Hook 与 useEffect 类似,但它会在浏览器渲染更新之前同步执行副作用操作,以确保 React 组件与浏览器同步更新。通常情况下,应该使用 useEffect,但在需要直接操作 DOM 元素或进行测量布局界面时,应当使用 useLayoutEffect。
  • useDebugValue:该 Hook 可以帮助开发者在调试工具中显示额外的信息,以便更好地理解 Hook 的使用和行为。通常情况下,这个 Hook 只用于调试过程中,而不是实际的应用程序代码中。

21、介绍下React中的useEffect

useEffect 的作用是在每次渲染后执行一些副作用操作,比如访问 DOM 元素、发送网络请求、设置定时器等。它接收两个参数:一个函数和一个可选的依赖数组。

  • 函数参数表示需要执行的副作用操作。该函数会在第一次渲染后和每次更新后执行。如果希望在组件卸载时执行某些清理操作,可以在该函数中返回一个清理函数。
  • 依赖数组参数是一个可选的数组,用于指定需要监视的变量。只有当依赖数组中的变量发生变化时,useEffect 才会重新执行。如果不传递依赖数组,则每次组件更新时都会执行该函数。

22、React中常用的高阶组件有哪些?

高阶组件可以用来复用组件逻辑、增强组件功能或者封装共享的代码。 以下是一些常用的高阶组件:

  • withRouter:withRouter 是 React Router 提供的高阶组件,用于将 history、location 和 match 对象传递给组件。这样可以让非路由组件也能获取路由信息。
  • connect(Redux):connect 是 React Redux 提供的高阶组件,用于连接 Redux 的 store 到 React 组件。通过 connect,组件可以访问 Redux store 中的状态和 dispatch 函数。
  • memo:memo 是 React 提供的用于性能优化的高阶组件。它可以缓存组件的渲染结果,只有在 props 发生变化时才会重新渲染组件。
  • forwardRef:forwardRef 是 React 提供的高阶组件,用于向子组件传递 ref。通常用于需要访问子组件实例的情况。
  • Provider(Context API):Provider 是 React Context API 提供的高阶组件,用于在组件树中向下传递数据。通过 Provider,可以在应用中使用全局的状态。
  • withStyles(Material-UI):withStyles 是 Material-UI 提供的高阶组件,用于处理组件样式。它可以将样式对象转换为 CSS 类名,并注入到组件中。
  • compose:compose 是 Redux 提供的高阶函数,用于组合多个高阶组件。通过 compose,可以将多个高阶组件串联起来,简化组件的嵌套。

23、介绍一下React Fiber

React Fiber是React框架中一种新的协调引擎,旨在改善渲染性能和用户体验。它通过引入优先级调度、增量渲染和可中断的工作单元等机制,将渲染任务分解成小的可中断的单元,从而使React能够更好地处理大型应用程序和高优先级任务,提供流畅且响应迅速的用户界面。

24、React Hook为什么不能放到条件语句中?

React 需要依赖 Hook 的调用顺序来正确地管理组件的状态。将 Hook 放在条件语句中可能导致 Hook 的调用顺序发生变化,从而破坏 React 对 Hook 调用顺序的依赖,引发一些潜在的问题。

如果将 Hook 放在条件语句中,那么在条件满足或不满足的情况下,Hook 的调用顺序可能发生变化,这将导致 React 无法准确地追踪每个 Hook 的状态变化,可能会导致组件状态错乱、重复渲染等问题。

将 Hook 的调用放在函数组件的最顶层,而不是嵌套在条件语句、循环中。这样可以确保每次渲染时 Hook 的调用顺序保持一致,帮助 React 正确地管理组件状态,保证组件的行为和预期一致。

25、Webpack中有哪些核心概念?

  • Entry(入口):Webpack在打包时需要从哪个文件开始构建依赖关系图,就是入口。可以设置多个入口文件,以生成多个输出文件。
  • Output(输出):打包后的文件放在哪里,以及如何命名这些文件。可以指定输出目录、文件名、公共路径等。
  • Loader(模块加载器):Webpack只能处理JavaScript文件,而其他类型的文件如CSS、图片等需要通过Loader转换才能被Webpack处理。Loader用于对模块内容进行转换处理。
  • Plugin(插件):Plugin可以用于执行各种任务,例如打包优化、错误处理和环境变量注入等。Webpack本身只提供了一些基本的Plugin,但社区中有很多第三方Plugin可供使用。
  • Mode(模式):Webpack提供了三种模式:development、production和none。不同的模式会启用不同的Webpack内置Plugin和Loader,以便于开发和生产环境的优化。
  • Chunk(代码块):Webpack在打包时会把所有相关联的模块组成一个Chunk。可以通过Code Splitting技术将代码拆分成多个Chunk,以实现按需加载。
  • Module(模块):Webpack把每个文件都看作一个模块,它可以是JavaScript、CSS、图片等。这些模块通过依赖关系进行组合,构成整个应用程序。

26、Vite 和 Webpack 的区别

  • 打包速度:Vite 的打包速度比 Webpack 更快。Vite 利用了浏览器原生 ES 模块的特性,在开发模式下无需将代码打包成一个文件,而是通过浏览器直接引入模块,从而大大提高了打包速度。
  • 开发体验:Vite 支持热更新,可以在修改代码后快速更新浏览器中的页面。同时 Vite 提供了可视化的构建信息和源码调试功能,可以帮助开发者更好地理解代码的运行情况。
  • 插件生态:Webpack 生态更加成熟,拥有更多的插件和 loader。但是 Vite 也支持大部分 Webpack 的插件和 loader,而且 Vite 本身已经集成了常用的功能,因此在某些场景下,使用 Vite 可以减少依赖和配置文件的数量,简化项目结构。
  • 构建目标:Webpack 可以构建多种类型的项目,包括 Web 应用、Node.js 应用、桌面应用等。而 Vite 更加专注于 Web 应用的构建。

27、Webpack常见的优化方案有哪些?

  • 代码分割(Code Splitting):通过代码分割,将代码拆分成多个小块,按需加载,可以减少首次加载时间,提高页面加载速度。可以使用 Webpack 的内置工具如 SplitChunksPlugin 来实现代码分割。
  • 懒加载(Lazy Loading):只在需要时再加载特定的模块,而不是一次性加载所有模块。可以通过动态 import 或使用 React.lazy、Vue异步组件等技术来实现懒加载。
  • Tree Shaking:通过去除未使用的代码,减少打包后的文件大小。可以通过配置 Webpack 的 mode 为 production 来启用 Tree Shaking 功能。
  • 缓存(Caching):利用浏览器缓存机制,避免重复加载已经加载过的资源,减少请求次数,提高页面加载速度。可以使用 Webpack 的 [contenthash] 或 [chunkhash] 来生成文件名,实现缓存控制。
  • 多进程打包:通过 Webpack 多进程打包,加快打包速度。可以使用 thread-loader 或 HappyPack 等插件来实现多进程打包。
  • 优化图片资源:对图片资源进行压缩、转换或使用 url-loader、file-loader 等加载器将小图片转成 base64 格式,减少请求次数和文件大小。
  • 优化字体文件:对字体文件进行压缩,将其转换为 base64 格式或使用 CDN 加载,减少文件大小和请求次数。
  • 代码压缩:使用 Webpack 插件如 terser-webpack-plugin 对代码进行压缩,减少文件大小,提高页面加载速度。

28、浏览器中强缓存与协商缓存的缓存机制

  • 强缓存通过设置响应头中的Cache-Control或Expires字段,告诉浏览器在一定时间内直接使用本地缓存,不需要发送请求到服务器。只有当缓存过期或被清除时,浏览器才会发送请求到服务器获取新的资源。
  • 协商缓存通过设置响应头中的ETag和Last-Modified字段,浏览器在每次请求时携带If-None-Match和If-Modified-Since字段,与服务器进行比较。如果资源未发生变化,则服务器返回304 Not Modified状态码,并告知浏览器继续使用缓存;如果资源发生变化,则服务器返回新的资源。

强缓存是基于时间的缓存控制,而协商缓存则是通过与服务器进行交互来判断是否使用缓存,更加灵活。

全部评论

相关推荐

2024-09-13一面不到残血不会玩前面回答的1t4后面抢救回来了1. 项目拷打2. 浅拷贝和深拷贝2plus. = 和 浅拷贝的区别3. 有什么方式实现深拷贝4. 原型5. 浏览器事件循环6. 输出题: promise输出题7. 数组的map和forEach有什么区别7plus. 可以在map里面修改原数组吗8. rem 和 em8plus. 如何使用rem做移动端适配9. 前端性能优化 => 具体到白屏优化10. 编程题: 数组去重 => 赛马的IDE很坑十分钟之后二面二面虽然挂了 但是总结了方法论1. 工作中成就的点2. 在项目中做了什么难点3. 项目优化4. v-if v-show5. display:none    visibility:hidden    opacity:0 有什么区别6. 为什么要用axios而不用原生的xhr或者fetch6plus. 场景题: 如果让你封装axios,你会怎么封装7. 编程题: URL的字符串拼接    给一个url和一个对象,把对象拼接到url的query参数里面反思挂的点:1. 开始的时候旁边有个大妈在打电话,环境嘈杂2. 项目难点有点普通,没有挑战性3. *** 反问的时候问了雷 ***    您觉得我有什么可以改进的地方        这个是你觉得自己挂了才会问的才知道虽然挂了有点可惜但是总算是挂了一个正常的二面了下次二面必拿下经验+10
滴滴二面213人在聊 查看20道真题和解析
点赞 评论 收藏
分享
6 18 评论
分享
牛客网
牛客企业服务