面试汇总

415 阅读22分钟

Html

1.H5新增了那些标签?

  语义化标签:`<header>`:头部标签 
             `<nav>`:导航标签
             `<section>`:块级标签       注释*
             `<article>`:内容标签         1.需要把它们转化为块级元素 display:block
             `<aside>`:侧边栏标签         2.主要用于移动端
             `<footer>`:尾部标签
  多媒体标签:`<video>`视频标签     `<audio>`音频标签
  
  图形标签:<canvas>
  
  本地离线存储(分为cookie和webStorage,而webStorage又分为localStorage和[sessionStorage]
              localStorage   sessionStorage   cookie
              
  input: number  date  time  email  url  search

C3新增了那些属性?(圆角、阴影、动画等等)

1.处理盒子塌陷?

  1、给父盒子添加`overflow:auto;`或者`overflow:hidden;`2、父盒子里最下方引入清除浮动块   <div style="clear:both"></div>
  3、为外部盒子添加after伪类,设置clear属性清除浮动(主流)
        父盒子::after {
         content: "";
         /* 清除两边的浮动 */
         clear: both;
         /* 也可以使用display:table; */
         display: block;
         /* 兼容IE浏览器 */
         zoom: 1;
         }

2.元素的水平居中、垂直居中方式?

  1、 text-align:center  line-height:元素高度
  2、 盒子模型
  3、 定位
  4、 flex布局

3.BFC?

  1、概述:块级格式化上下文。你可以把BFC看做一个容器,容器里边的元素不会影响到容器外部的元素。
  2、特性:1.  BFC是一个块级元素在垂直方向上依次排列。
          2.  BFC是一个独立的容器,内部元素不会影响容器外部的元素。
          3.  属于同一个BFC的两个盒子,margin会发生重叠,并且取最大外边距。
  3、 创建BFC?
      **给父级元素添加以下任意样式**
         1.  overflow: hidden;
         2.  display: flex;
         3.  display: inline-flex;
         4.  display: inline-block;
         5.  position: absolute;
         6.  position: fixed;
  4、 作用?
      1、解决当父级元素没有高度时,子级元素浮动会使父级元素高度塌陷的问题(清除浮动)
      2、解决子级元素外边距会使父级元素塌陷的问题(清除塌陷)

4.回流(重排)和重绘

    回流:布局发生改变
    重绘:样式发生改变
    区别:回流必定会引起重绘,重绘一定不会引起回流,回流会导致页面重排,影响性能

5.css中有哪些方式可以隐藏页面元素?区别是什么?

  1. display: none 脱离文档流 无法响应事件 回流重绘
  2. visibility: hidden 占据文档流 无法响应事件 重绘
  3. opacity: 0 占据文档流 响应事件 重绘 || 不重绘
  4. position: absolute 脱离文档流 无法响应事件 回流重绘
  5. clip-path: circle(0%) 占据文档流 无法响应事件 重绘

6.pxemremvwvh 是用来表示长度单位的,区别是什么?:

  1. px(像素): px 是绝对单位,表示屏幕上的实际像素(元素大小不会随着视口的改变而改变)。
  2. em:em 是相对单位,它相对于其父元素的字体大小来计算(如果父元素的字体大小是 16px,那么 1em 就 等于 16px)
  3. remrem 是相对单位,它相对于根元素(html 元素)的字体大小来计算
  4. vwvhvw 表示视口宽度的百分比,100vw 等于视口的宽度,vh 表示视口高度的百分比,100vh 等于视口的高度

总结:

  • 使用 px 可以精确控制元素的大小,但不利于响应式设计。

  • 使用 em 和 rem 可以根据父元素或根元素的字体大小来调整元素的大小,适合用于相对大小的设计。

  • 使用 vw 和 vh 可以根据视口大小来设置元素的大小,适合用于响应式设计。

js方面

let const 区别

  1. 都是块级作用域、不能重复声明
  2. let存在暂时性死区问题 const声明必须赋值,且这个值不能改变,当属性值为对象是可以改变
"暂时性死区"Temporal Dead Zone,简称 TDZ)是指在 JavaScript 中使用 letconst 声明变量时,
该变量在声明之前无法被访问的现象。在变量声明之前对其进行访问会导致 ReferenceError 错误。

//举个例子来说明暂时性死区
console.log(myVar); // ReferenceError: Cannot access 'myVar' before initialization
let myVar = 10;

ES6常用的方法有哪些?

  • Promise
`Promise 是异步编程的一种解决方案
`Promise`对象代表一个异步操作,有三种状态:`pending`(进行中)、`fulfilled`(已成功)和`rejected`(已失败)`
一旦状态改变,就不会再变,一旦新建它就会立即执行,无法中途取消,`Promise`对象的状态改变,只有两种可能:
从`pending`变为`fulfilled`或者从`pending`变为`rejected``Promise`构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject
`resolve:(pending--->fulfilled)`
`reject:(pending--->rejected)`//异步加载图片举例:
function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    const image = new Image();
    image.onload = function() {
      resolve(image);
    };
    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };
    image.src = url;
  });
}

Promise其他的一些常用的方法:
`Promise.all()` 方法是一个用于处理多个 Promise 实例的方法,它接收一个 Promise 对象数组作为参数,
并返回一个新的 Promise 对象。这个新的 Promise 对象在传入的所有 Promise 对象都成功(resolved)时才会变
为成功状态,如果其中有任何一个 Promise 对象失败(rejected),那么这个新 Promise 对象就会立即变为失败状态。

    const promise1 = new Promise((resolve, reject) => {
            setTimeout(() => { resolve('Promise 1 resolved')}, 1000);
         });
    const promise2 = new Promise((resolve, reject) => { 
            setTimeout(() => { resolve('Promise 2 resolved')}, 2000)
         });
    const promise3 = new Promise((resolve, reject) => {
            setTimeout(() => { resolve('Promise 3 resolved')}, 1500)
         });
         
    Promise.all([promise1, promise2, promise3]) .then((results) => {
            console.log('All promises resolved:', results); 
        }) .catch((error) => { 
            console.error('At least one promise rejected:', error);
        });
        
`Promise.allSettled()`方法与Promise.all很相似,但不同的是
Promise.all传入的所有 Promise 对象都成功(resolved)时才会变为成功状态(fulfilled),
Promise.allSettled是传入的所有 Promise 对象只有等到参数数组的所有 Promise 对象都发生状态变更
(不管是`fulfilled`还是`rejected`),返回的 Promise 对象才会发生状态变更


`Promise.race()和Promise.any()`
Promise.any:只要参数实例有一个变成`fulfilled`状态,包装实例就会变成`fulfilled`状态;
             如果所有参数实例都变成`rejected`状态,包装实例就会变成`rejected`状态。

Promise.race:任何一个 Promise 对象的状态发生变化(无论是成功还是失败)时,
             就会采用该 Promise 对象的状态作为返回的新 Promise 对象的状态。
  • 闭包
闭包:内部函数调用外部函数的参数和变量

闭包的主要用途包括:

1.  保护变量:通过闭包,可以创建私有变量,只有内部函数可以访问和修改这些变量,外部代码无法直接访问,从而提供了一定程度的数据封装和保护。
2.  延续局部变量的生命周期:内部函数可以引用外部函数的变量,即使外部函数已经执行完毕,这些变量依然存在于内部函数的作用域中,从而延续了变量的生命周期。
3.  实现柯里化和偏函数应用:通过闭包,可以将多参数的函数转化为接受部分参数的函数,从而方便地实现柯里化和偏函数应用。

闭包可能会导致内存泄露

解决:使用完时候消费掉

举例:
function createCounter() { 
    let count = 0; return function increment() { 
        count++; console.log(count);
        if (count >= 10) { 
        count = null; // 及时释放引用 
        } 
    }; 
} 
const counter = createCounter(); // 当不再需要计数器时,手动将 count 设置为 null 释放对其的引用

  • 原型、原型链
每个对象都有一个__proto__属性,指向构造函数的prototype。


原型、构造函数、实例、原型链的关系如何?
  构造函数(Constructor):构造函数是用来创建对象的函数。当使用 new 关键字调用构造函数时,
        会创建一个新的对象,并且该对象会继承构造函数的属性和方法。
原型(Prototype):每个 JavaScript 对象都有一个原型(prototype),原型是对象与其他对象的链接。
        通过原型,对象可以继承另一个对象的属性和方法。
实例(Instance):实例是通过构造函数创建的具体对象。每个实例都拥有自己的属性和方法,
        同时也可以访问构造函数原型中定义的属性和方法。
原型链(Prototype Chain):当需要访问一个对象的属性或方法时,JavaScript 引擎会先查找对象本身是否拥有
       这个属性或方法,如果没有,就会沿着原型链向上查找。原型链是由对象的原型指向构成的链式结构,
       直到最顶层的 Object.prototype
  • 箭头函数(箭头函数与普通函数的区别)

    1. 简洁的语法:箭头函数使用(参数) => { 函数体 }的形式来定义,相比传统的函数声明方式更为简洁。
    2. 隐式的返回值:当函数体只有一条语句时,箭头函数会隐式返回该语句的结果,无需使用return关键字。
    3. 没有自己的this:箭头函数没有自己的this值,它会继承外层作用域的this。这意味着在箭头函数内部,无法使用this来引用函数本身,而是继承了外部作用域的this
    4. 不能作为构造函数:箭头函数不能通过new关键字调用,因此不能用作构造函数来创建对象实例。
    5. 不能绑定arguments对象:箭头函数没有自己的arguments对象,它会继承外层作用域的arguments对象。
  • 模板字符串

  • 解构赋值

  • Es6数组新增了哪些方法?(扩展运算符、Array.form、fond和findIndex、includes、flat等等)

  • 阮一峰老师(es6.ruanyifeng.com/

防抖、节流函数

防抖:防抖是触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。适用于可以多次触发但触发只生效最后一次的场景。(最后一次执行)

/**防抖*/
function handleFd(fn,delay=500){
    let timer
    return function(){
        const args = arguments
        if(timer){
            clearTimeout(timer)
        }
        timer = setTimeout(()=>{
            fn.call(this,args)
        },delay)
    }
}

节流:节流是高频事件触发,但在n秒内只会执行一次,如果n秒内触发多次函数,只有一次生效,节流会稀释函数的执行频率。(每隔一段时间执行一次)

/**节流*/
function handleJl(fn,delay=500){
    let timer = true
    return function(){
        const args = arguments
        if(timer){
            return
        }
        timer = flase
        timer = setTimeout(()=>{
            fn.call(this,args)
            timer = true
        },delay)
    }
}

深浅拷贝

/**
*深拷贝:将一个对象从内存中完全拷贝出来,在内存中开辟一个新的空间存放这个对象,两者互不影响
*实现方式:1、JSON.parse(JSON.stringify(obj)) 缺点:
*如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
*如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
*2、通过递归实现深拷贝(代码如下)
*/
function deepClone(source){
  const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for(let keys in source){ // 遍历目标
    if(source.hasOwnProperty(keys)){
      if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
        targetObj[keys] = source[keys].constructor === Array ? [] : {};
        targetObj[keys] = deepClone(source[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = source[keys];
      }
    }
  }
  return targetObj;
}

/**浅拷贝:创建一个新的对象,将这个对象的原始属性完全拷贝一份,如果是基本类型,就拷贝基本类型的值,
如果是引用数据类型,拷贝的就是内存里的值,如果其中一个引用类型的值发生了改变,就会影响另一个值*/
//object.assign({},obj)
//扩展运算符、concat

apply、call、bind的区别?

相同点:都可以改变this的指向,第一个参数都是this要指向的对象
不同点:apply与call方法相似,不同之处在于传参的形式不一样,apply是以数组的形式传参
       apply与call方法在改变this指向是会立即执行,而bind是稍后执行,而是返回改变this
       后的新方法

事件循环{主线程>微任务(promise)>宏任务(定时器函数)}

事件循环JS是单线程的,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环机制。在JS中把任务分为同步和异步,同步任务和异步任务的执行环境不同,同步任务会进入主线程,异步任务会进入EventQueue(事件队列),主线程中的任务执行完毕后,回去EventQueue中读取对应的任务,并推到主线程中执行,不断重复过程,称为EventLoop(事件循环机制) 理解这里很重要!

    <script>
        console.log('同步任务1')
        setTimeOut(()=>{
           console.log('setTimeOut是个宏任务')
        },0)
        new Promise((reslove,reject)=>{
            console.log('遇到new,Promise立即执行')
            reslove()
        }).then(()=>{
            console.log('Promise.then是个微任务')
        })
        
       console.log('同步任务2')
    </script>
    
 //打印结果:同步任务1 遇到new,Promise立即执行 同步任务2 Promise.then是个微任务 setTimeOut是个宏任务
常见的微任务有
-   Promise.then
-   Proxy对象替代
-   process.nextTick
-   MutaionObserver

常见的宏任务
-   整个script
-   setTimeout/setInterval
-   UI rendering/UI事件
-   setImmediate、I/O

当点击 button 时,浏览器的事件流是怎样触发的 ?

在浏览器中,当用户点击一个按钮时,事件流描述了事件(如点击事件)在DOM树中传播的顺序。事件流分为两个主要的模型:冒泡事件流和捕获事件流。

以下是一个简化的说明,描述了从点击按钮到事件处理函数被调用的整个过程:

  1. 事件捕获阶段

    • 事件首先从文档的根元素(document对象)开始,然后逐级向下传播到目标元素。
    • 在这个阶段,浏览器检查是否有在捕获阶段注册的事件监听器,如果有,这些监听器将被调用。
  2. 目标阶段

    • 事件到达目标元素(在这个例子中是按钮元素)。
    • 在目标元素上注册的所有事件监听器(无论它们是在捕获阶段、冒泡阶段还是两者都有)都会按照注册的顺序被调用。
  3. 事件冒泡阶段

    • 事件从目标元素开始,逐级向上传播回文档的根元素。
    • 在这个阶段,浏览器检查是否有在冒泡阶段注册的事件监听器,如果有,这些监听器将被调用。

关闭Windows.open()弹出的窗口后,如何刷新父页面?

//在关闭弹窗的按钮上添加一下代码?
const flag = window.open(url)
const loop = setTimeOut(()=>{
    if(flag.closed){
        clearTimeOut(loop)
        parent.location.reload()
    }
},500)

Vue面试题

1. vue双向数据绑定原理?

是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty() 来劫持 各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调从而达到数据和视图同步。

2. diff算法

diff 算法是一种通过同层的树节点进行比较的高效算法,比较方式:diff整体策略为:深度优先,同层比较 diff算法 当data发生改变 会根据新的数据生成一个新的虚拟dom ,新的虚拟dom和旧的虚拟dom进行对比, 这个对比的过程就是diff算法,会找到不同地方,只去渲染不同的地方,总的来说就是减少DOM,重绘和回流。

3.虚拟dom

虚拟dom 是一个 JavaScript 对象,通过对象的方式来表示 DOM 结构。将页面的状态抽象为 JS 对象的形式,配合不同的渲染工具,使跨平台渲染成为可能。通过事务处理机制,将多次 DOM 修改的结果一次性更新到页面上,从而有效的减少页面渲染的次数,减少修改DOM的重绘重排次数,提高渲染性能。

4. vue的响应式原理?

get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来, 最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上

5.vue生命周期

  1. beforeCreate 创建前,这个时候data中的数据,还未定义,所以不能使用

  2. created创建后 最早开始使用 data和methods中数据的钩子函数

  3. beforeMount 挂载前 指令已经解析完毕内存中已经生成dom树,但是尚未挂载到页面中去,此时页面还是旧的。

  4. mounted 挂载后 dom已经渲染完毕,此时页面和内存中都是最新的数据,最早可以操作DOM元素钩子函数

  5. beforeUpdate 更新前 当视图层的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新,数据没有与页面同步

  6. updated() 更新后 数据更新完成以后触发的方法,DOM节点已经更新

  7. beforeDestroy 即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作

  8. destroyed 销毁完毕 组件已经全部销毁,Vue实例已经被销毁,Vue中的任何数据都不可用

  9. activated 被 keep-alive 缓存的组件激活时调用。

  10. deactivated 被 keep-alive 缓存的组件停用时调用。

Vue2生命周期钩子函数Vue3选项式APIVue3组合式API描述
beforeCreatebeforeCreatesetup()创建前,此时datamethods还没有初始化
createdcreatedsetup()创建后,data中有值,尚未挂载,可以进行一些Ajax请求
beforeMountbeforeMountonBeforeMount()挂载前,会找到虚拟DOM,编译成Render
mountedmountedonMounted()挂载后,DOM已创建,可用于获取访问数据和DOM元素
beforeUpdatebeforeUpdateonBeforeUpdate()更新前,内存更新,但是DOM节点还未更新,数据没有与页面同步
updatedupdatedonUpdated()更新后,数据更新完成以后触发的方法,DOM节点已经更新,所有状态已是最新
beforeDestroybeforeUnmountonBeforeUnmount()销毁前,即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作,可用于一些定时器或订阅的取消
destroyedunmountedonUnmounted()销毁后,可用于一些定时器或订阅的取消
activatedactivatedonActivated()keep-alive缓存的组件激活时
deactivateddeactivatedonDeactivated()keep-alive缓存的组件停用时
---renderTrackedonRenderTracked()调试钩子,响应式依赖被收集时调用
---renderTriggeredonRenderTriggered()调试钩子,响应式依赖被触发时调用
---serverPrefetchonServerPrefetch()组件实例在服务器上被渲染前调用

6.created和mount的区别?

  1. created 是最早修改data的最早时机
  2. mounted 是最早改变dom的最早时机

7.vue父子组件生命周期执行顺序

  1. 加载渲染过程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
  2. 子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
  3. 父组件更新过程:父beforeUpdate->父updated
  4. 销毁过程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

补充:第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

8.$nextTick的作用

nextTick中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个 方法,获取更新后的DOM。使用场景:可以在created钩子函数中拿到dom节点

9.组件间的通信方式

  1. 父到子(props)
  2. 子到父($emit)
  3. 兄弟间传值(eventBus)
  4. $ref
  5. Vuex

10.Vue组件中data为什么是一个函数?为什么写一个返回值?

为了保证函数独立性和复用性,data是一个函数,组件实例化的时候这个函数将会被调用,返回一个 对象使用return包裹后数据中的变量只在当前组件中生效,不会影响其他组件,不使用return包裹的数据 在项目中全局可见,会造成数据污染

11.Vue中key值的作用?

使用key来给每一个节点添加一个唯一标识,可以根据key,更准确, 更快的找到对应的vnode节点, 更高效的对比虚拟DOM中每个节点是否是相同节点,相同就复用,不相同就删除旧的创建新的 主要作用:高效的更新虚拟DOM

12.用自定义指令做过那些事情?

1.输入框的自动聚焦
 <el-input v-focus v-model="item.name" @blur="() => (item.isEdit = false)" autofocus />
 directives: {
    //自定义输入框每次出现都聚焦的指令
    focus: {
      inserted: function (el) {
        el.focus()
      }
    }
  }
2.Vue自定义指令实现按钮级权限
<a href="https://blog.csdn.net/qq_45710388/article/details/123143610">

blog.csdn.net/qq_45710388…

13.Vue事件修饰符?

  1. .stop 阻止事件冒泡 (阻止传播:stopPropagation())
  2. .prevent 阻止默认行为 (取消默认事件行为:preventDefault())
  3. .capture 捕获事件
  4. .self 仅绑定自身元素
  5. .once 只执行一次点击

14.v-model 的修饰符?

  1. .lazy 通过这个修饰符,转变为在 change 事件再同步
  2. .number 自动将用户输入值转化为数值类型
  3. .trim 自动过滤用户输入的收尾空格

15.routeroute和router的区别?

  1. $route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
  2. $router是“路由实例” 对象包括了路由的跳转方法,钩子函数

跳转路由的方式:1、this.router.push()2this.router.push() 2、this.router.go(-1) 3、router-link

16.vue-router的两种模式?

  1. hash模式:location.hash的值实际就是URL#后面的东西,特点:hash虽然出URL中,但不会被包含 在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面

  2. history模式利用了HTML5 Histoty Interface中新增的pushState()和replaceState()方法 特点:前端的url和后端发起请求的url需要一致(否则会报404的错误),需要和后端进⾏配合

17.params和query的区别?

  1. 属性名不同:query一般使用path,params使用name
  2. 传参不同:query类似 get,跳转之后页面 url后面会拼接参数,类似?id=1。params类似 post,跳转之后页面 url后面不会拼接参数
  3. 取参不同:this.route.query.xxxthis.route.query.xxx this.route.params.xxx

18.GET和POST的区别?

  1. get参数通过url传递post放在请求体
  2. get请求在url中传递的参数是有长度限制的,而post没有
  3. postget更安全,因为get参数都暴露在url中
  4. get请求只能进行url编码,而post支持多种编码格式

19.Computed和Watch的区别?

  1. computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的 属性值发生改 变,下一次获取 computed 的值时才会重新计算 computed 的值。 使用场景:购物车
  2. watch 侦听器 : 更多的是观察的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化 时都会执行回调进行后续操作。 使用场景:输入框

20.怎样理解 Vue 的单项数据流?

数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数 据进行修改。这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解。

21.vue性能优化

  1. 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
  2. v-if和v-for不能连用
  3. 如果需要使用v-for给每项元素绑定事件时使用事件代理
  4. SPA 页面采用keep-alive缓存组件
  5. 在更多的情况下,使用v-if替代v-show
  6. key保证唯一
  7. 使用路由懒加载、异步组件
  8. 防抖、节流
  9. 第三方模块按需导入
  10. 长列表滚动到可视区域动态加载
  11. 图片懒加载

22.Vue 中强制更新视图的几种方式

方法一:Vue.set() 方法(this.$set())
        Vue.set( target, key, value ) 中有三个参数
        target:要更改的数据源(可以是对象或者数组)
        key:要更改的具体数据 如果是数组 就是索引值
        value :重新赋的值
        
        例:this.$set(this.student,"age", 24)
        
方法二:this.$forceUpdate();

23.怎么解决Vue.js初始化闪屏问题

<div v-cloak>{{ title }}</div>
[v-cloak]{ display:none; } 

24.什么是SPA?

SPA(Single Page Application:单页面应用)是一种 Web 应用程序的架构模式,它通过动态加载页面内容,实现在单个页面中提供整个应用程序所需的功能和交互体验,而无需每次加载新页面。这种应用程序通常以 JavaScript、HTML 和 CSS构建,并利用 AJAX 技术从服务器异步请求数据

SPA 的一些特点和优势:

  1. 无需刷新页面:SPA 在加载初始页面后,通过 AJAX 技术动态获取数据并更新页面内容,实现无需刷新整个页面的交互体验,用户可以流畅地浏览应用。
  2. 快速响应:由于 SPA 只需要加载一次页面,后续的页面内容更新都是通过 AJAX 请求实现,因此可以实现快速的页面切换和响应,提高用户体验。
  3. 前后端分离:SPA 通常采用前后端分离的架构,前端负责 UI 展示和交互逻辑,后端提供 API 数据接口,使得开发和维护更加灵活和高效。
  4. 路由管理:SPA 使用客户端路由管理,通过 URL 的 hash 或 HTML5 History API 实现页面间的切换和导航,同时可以实现页面状态的保存和回溯。
  5. 缓存和性能优化:SPA 可以通过缓存技术将部分数据或页面缓存到客户端,减少重复请求和提升性能,同时也可以实现按需加载资源,减小首次加载时的资源体积。
  6. 交互体验:由于 SPA 可以实现动态更新页面内容,因此可以实现丰富的交互效果和动画,提升用户体验和吸引力。

SPA 的一些劣势:对 SEO 不友好、 首次加载时间较长、内存管理等问题需要考虑和解决

解决方法:

  1. 服务器端渲染(SSR) :使用服务器端渲染可以改善对 SEO 的支持,因为搜索引擎可以更轻松地索引页面内容。通过在服务器端生成页面内容,可以减少客户端加载时间,并提高首屏加载速度。
  2. 代码分割:将应用程序拆分为多个较小的模块,按需加载,可以减少首次加载时间。这样可以确保用户只下载当前页面所需的代码,而不是整个应用程序。
  3. 图片和资源优化:优化图片和其他资源的大小和格式,以减少页面加载时间。使用适当的压缩技术和格式可以帮助提高页面性能。
  4. 懒加载(Lazy Loading) :延迟加载页面中的某些内容,如图片、视频或其他资源,直到用户需要访问它们。这可以减少初始加载时间,提高页面响应速度。
  5. 内存管理:确保及时释放不再需要的资源和内存,避免内存泄漏。定期检查代码,优化内存使用,尤其是在大型应用程序中。
  6. 缓存策略:合理设置缓存策略,利用浏览器缓存和服务端缓存来减少重复加载资源的次数,提高页面加载速度。
  7. 性能监控:使用工具监控应用程序的性能表现,识别潜在的性能瓶颈,并进行相应的优化和改进。
  8. 移动优化:确保应用程序在移动设备上的性能和用户体验良好。优化移动端页面布局、图片大小等,以提高移动设备上的加载速度和用户体验。

Vuex

1.vuex是什么?

vue框架中状态管理。

2.vuex有哪几种属性?

有五种,State、 Getter、Mutation 、Action、 Module
state: 基本数据(数据源存放地)
getters: 从基本数据派生出来的数据
mutations : 提交更改数据的方法,同步!(更改state中状态的唯一方法) this.store.commit()
actions : 像一个装饰器,包裹mutations,使之可以异步。this.store.dispatch()
modules : 模块化Vuex

Http

1.http常见的状态码

200:请求成功。一般用于GET与POST请求
300:重定向
400:客户端请求的语法错误,服务器无法理解
401:请求要求用户的身份认证
403:服务器理解请求客户端的请求,但是拒绝执行此请求(没有权限)
404:服务器无法根据客户端的请求找到资源(网页)
500:服务器内部错误,无法完成请求

2.http和https的区别?

1、端口:https的端口是443,而http的端口是80,当然两者的连接方式也是不太一样的。

2、传输数据:http传输是明文的,而https是用ssl进行加密的。https具有安全性

3、申请证书:https传输一般是需要申请证书,申请证书可能会需要一定的费用。而http不需要

3.强缓存和协商缓存?

强缓存:浏览器不会像服务器发送任何的请求,直接从本次存储中读取文件并返回Status Code:200 ok

强缓存就是本地缓存,浏览器首次请求资源后,需要再次请求时,浏览器首先获取该资源缓存的header信息,然后根据
Cache-Control和expires来判断该资源在本地缓存中是否过期,若没有过期则直接从本地缓存中获取资源信息,浏览
器就不再向服务器重新请求资源,如过期需要重新发送请求,重新缓存资源,更新缓存的时间

协商缓存:是服务区用来确定缓存资源是否可用过期

向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返
回304状态码并带上新的response header通知浏览器从缓存中读取资源


总结:
-     强制缓存和协商缓存都针对静态资源,动态资源实现缓存方法参考上方伪代码。
-     强制缓存在前,协商缓存在后。
-     资源未过期触发强制缓存,资源过期后再触发协商缓存。
-     判断过期的方法expires(绝对时间)、cache-control(相对时间)
-     判断资源是否有更新(Last-Modified 和 ETag)

4.说一下用户输入完Url按下回车,看到网页的过程发生了什么?

1、URL解析
2、DNS域名解析
3、建立tcp连接(三次握手)
4、发送http请求
5、服务器处理请求并返回Http报文
6、浏览器解析渲染页面

juejin.cn/post/684490…

5.浏览器渲染页面过程?

1. 解析html代码,生成DOM tree
2. 解析css代码,生成CSSOM tree
3. 通过DOM tree 和 CSSOM tree 生成 Render tree
4. Layout(布局),计算Render tree中各个节点的位置及精确大小
5. Painting(绘制),将render tree渲染到页面上