vue 高级前端总结(—)

目录

1、闭包的理解

2、防抖、节流

3、BFC

4、原型

5、挂载与渲染

6、事件轮询

7、Promise

8、async/await

9、事件

事件机制有 3 种

事件委托

10、axios

11、跨域

如何解决跨域:

预检请求

 12、浏览器输入url到解析的过程

 1、浏览器查看缓存,没有发起新请求,有缓存,检验是否新鲜,足够新鲜直接返回给客户端,否则与服务器交互,通常是Expires 和 Cache-Control控制是否新鲜

2、浏览器解析URL获取协议,主机,端口,路径

3、浏览器封装一个http(GET)请求报文

4、获取主机ip,过程:浏览器缓存->主机缓存->host文件->路由器缓存->DNS缓存->DNS递归查询

5、打开一个socket,与目标地址建立TCP连接,三次握手连接,TCP连接后,发送http请求

6、服务器将响应报⽂通过TCP连接发送回浏览器

7、对响应进行解码(例如gzip压缩),如资源为html文件,解析html文件,构造Dom树,下载资源,构造CSSOM树,执行js脚本,解析过程中遇到图⽚、样式表、js⽂件,启动下载

(解析 html -词法分析然后解析成 dom 树、解 析 css ⽣成 css 规则树、合并成 render 树,然后 layout 、 painting 渲染、复合图 层的合成、 GPU 绘制、外链资源的处理、 loaded 和 DOMContentLoaded 等)

8、JS 引擎解析过程( JS 的解释阶段,预处理阶段,执⾏阶段⽣成执⾏上下⽂, VO ,作 ⽤域链、回收机制等等)

13、网站性能优化


1、闭包的理解

是什么: 闭包是一种技术,内部定义的函数可以访问外部函数的变量和参数

(即使外部函数已经执行完毕,任然可以访问这些变量和参数),

优点:可以用来解决异步编程保存变量,模块化编程实现私有变量

缺点:占用内存,使用不当会内存泄漏

function add(y) {
    function addx(x) {
        return x+y;
    }
    return addx;
}
let a = add(10);
console.log(a(2));

2、防抖、节流

防抖:在特定的触发事件的时间里,等待一段时间再执行,只执行最后一次(新数据)

应用:输入框弹表情,搜索框

let timer = null;
if(timer){
    clearTimeout(timer);
}
timer = setTimeout(()=>{
    fun(...args) // 需要执行防抖的函数
},10)

节流:固定的时间/频率去执行事件,第一次生效(旧数据)

应用:玩家的普攻,射击,页面滚动,拖拽

let timer = null;
if(!timer){
    timer = setTimeout(()=>{
    fun(...args)
    timer = null;
    },10)
}

3、BFC

块格式化上下文(Block Formatting Context,BFC)是 Web 页面的可视 CSS 渲染的一部分,它会创建一个只有块级盒子参与布局的不受外界布局影响的特殊区域

解决问题:文字环绕、浮动时的高度坍塌、外边距折叠和外边距穿透都可用BFC来解决,阻止父子margin的重叠


特点:同一个BFC的两个相邻元素的上下margin会发生重叠


BFC的触发条件:
根元素(HTML标签)
浮动float、绝对定位postion = fixed / absolute
overflow值不为visible的块元素(hidden,auto,scroll)   
display = inline-block、table-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid

4、原型

1、每个构造函数在创建的时候,都会伴生一个原型对象,每个构造函数都具有显式原型属性prototype,每个实例对象都具有隐式原型属性__proto__,并目实例对象的隐式原型指向了构造函数的是显式原型。所有的原型对象都具有 constructor 属性,指向自己对应的构造函数
    
    2、如果一个实例对象想要使用一个属性或方法,但是自身并没有,js就会顺着__proto__属性向上查找,找到对应构造函数的原型对象,如果原型对象上具有该属性或方法,那么就使用,没有则继续向上查找,直到找到 Object 构造函数的原型对象,有就使用,没有的话。查找的是属性就返回undefined,查找的是方法调用就会报错!至此,原型链的查找也到头了。

   3、把实例对象都具有的属性或方法放在原型对象上,最终目的就是节省内存空间,方便大家使用!
    
    4、原型的使用:在创建构造函数后,在其原型上增加想要使用的属性或方法,然后 new 构造函数后产生的实例对象就可以使用在构造函数的原型上增加的属性或方法了!使用场景: Vue 中,全局事件总线 $bus 就应用到原型链了(Vue.prototype.$bus = new Vue())

5、挂载与渲染

挂载:将 DOM 节点插入到 html 元素中

渲染:浏览器根据 html 元素的内容,绘制到页面上给用户观看

执行解析js代码的是js引擎(又称为js线程)
负责页面渲染的是GUI线程
GUI线程和JS线程,两者是互斥的


 首次渲染页面流程:首先执行主线程代码->清空微任务队列(promise.then)->GUI线程渲染页面->执行下一个宏任务
 更新页面流程:清空微任务队列->GUI线程渲染页面->执行下一个宏任务


问题:明明已经有宏任务了,为什么ES6还要新增微任务?
回答:前提:对页面的节点进行十万次的操作如果每个宏任务中,都修改一次页面,那么页面一共渲染10万次页面,如果每个微任务中,都修改一次页面,那么页面一共渲染1次页面,可以在微任务中多次修改页面,浏览器最终会根据最后一次的结果渲染页面,其实就是实现了函数防抖效果(Vue就是在微任务中更新DOM的)

6、事件轮询

1、浏览器的轮询机制

浏览器的轮询机制很简单,由于浏览器有非常多的兄弟帮忙,即是说浏览器是一个多进程、多线程的程序,所以 js 引擎实际负责的事情就相对较少!例如:在代码中使用 setTimeout 开启定时器,或者使用 ajax 发送请求等,js 线程就会将这类任务交给对应的管理模块进行管理,每个管理模块就是一个分线程,在满足条件之后,会自动往对应的任务队列中放入回调函数,

浏览器只有一个宏任务队列和一个微任务队列;事件循环的实际流程就是:浏览器将主线程代码执行结束之后,它就会在微任务队列和宏任务队列之间来回轮询,执行完微任务再去看宏任务,执行完宏任务又去看微任务

2、Node 事件轮询机制

在 node 中的事件轮询机制呢,与浏览器的轮询机制不太一样,它主要分为六个阶段,每个阶段都是一个独立的宏任务队列,也就是说 node 中有 6 个宏任务队列,其中最主要的就是第 1、第 4、第 5 三个阶段,第 1 阶段是 timers 定时器阶段(这也是入口阶段),第 4 阶段专门负责 I/O 操作相关内容(该阶段也是事件轮询的休息区),第 5 阶段是 setImmediate 专用阶段(是执行 setImmediate 设置的回调函数,它是 node 专用的)

对于 node 中的微任务,node 中具有.then 和 nextTick 两种微任务,如果他们两个都存在,nextTick 先于.then 执行,并且 node 具有两个微任务队列,一个是.then 专用的,另一个是 nextTick 专用的!(执行微任务需要注意:微任务队列是保证清空,只要队列里面有微任务,你就不能离开当前队列,必须清空才能跳到下一个队列);node 事件轮询是从 1~6 阶段,结束之后再从 1~6 阶段,必须走完全程才能走下一次轮询,不会出现跳阶段的情况。
 

7、Promise

Promise 是 js 中的一个原生对象,是一种异步编程的解决方法,可以替换掉传统的回调函数解决方案;它通过引入一个回调,避免更多的回调;简单来说 Promise 就是一个容器,里面保存着某个未来才会结束的事件的结果(通常是一个异步操作);new Promise()时,它可以接收 1 个参数,该参数是一个函数,这个函数又称为执行器函数,Promise 实例一经创建,执行器函数会被立即调用!这个执行器函数接收两个形参,resolve 和 reject,它们都是回调函数,resolve 方法被调用之后,会将 new Promise()生成的实例对象的状态变为成功状态,reject 方法被调用之后,会将 new Promise()生成的实例对象的状态变为失败状态,promise 对象具有两个重要属性:

1.  state => 代表当前 promise 对象的状态,

状态分为三种:pending 进行中(初始状态)、resolved/fulfilled 成功状态、rejected 失败状态

2.  result => 代表当前 promise 对象成功或失败状态的结果值

每个 Promise 对象都可以使用.then 链式调用,.then 调用的返回值是一个全新的 Promise,它的用处就是:监视前一个 promise 对象的状态的变化,并根据发生的变化执行对应的回调函数

.catch 作用:用于监视 promise 对象的状态变化,如果变为失败状态,就执行.catch 调用中传入的失败回调函数!

.catch 的返回值也是一个全新的 promise 对象

.catch 其实是.then 的语法糖,.catch( (err) => {} ) 等同于 .then( undefined, () => {} )

8、async/await

前言:什么是回调地狱

回调地狱就是在回调函数中再嵌套回调函数的情况,它也是实现代码顺序执行的一种操作方式,但是这种方式代码的可读性差、可维护性差、扩展性差;解决回调地狱的最初的方案就是 Promise,他还有一个最终的解决方案,就是 async/await 这个语法糖

1. 是什么?
   async、await 是 ES6+新增的 Promise 和.then 的语法糖
2. 为什么?为什么要使用 async、await?
   他们是解决回调地狱的终极方案,可以实现以同步的流程书写异步的代码

methods: {
    getLocation(phoneNum) {
         return axios.post('/one接口', {
             phoneNum
         })
     },    
     getFaceList(province, city) {
         return axios.post('/two接口', {
             province,
             city
         })
     },  
    async getFaceResult () {
                let location = await this.getLocation(this.phoneNum);
                if (location.data.success) {
                    let province = location.data.obj.province;
                    let city = location.data.obj.city;
                    let result = await this.getFaceList(province, city);
                    if (result.data.success) {
                        this.faceList = result.data.obj;
                    }
                }
            }
    }

9、事件

事件就是在编程时程序中发生的事情或者操作,简单来说就是用户做了哪些操作,比如说点击事件,鼠标移入、移出事件等

onclick 当鼠标单击的时候会触发 ondblclick 当鼠标双击的时候会触发

onmouseover 当鼠标悬停触发 onmousemove 当鼠标移动触发 onmouseout 当鼠标移出触发

onkeyup 当键盘弹起触发 onkeydown 当键盘下压触发

JS高级特性

事件机制有 3 种

一是事件捕获机制,

二是 IE 的事件冒泡机制;

三是标准事件机制(又称为标准事件流,是 W3C 推出的,这也是目前绝大多数的浏览器都使用的)。标准事件机制中又划分为三个阶段,1.捕获阶段(外到内):从最外层 document 开始,向内层逐层触发同类型事件,直到最内层的目标元素为止,2.目标阶段:将目标元素身上所有的同类型事件都触发,3.冒泡阶段(内到外):从最内层的目标元素开始,向外逐层触发同类型事件,直到 document 为止
JavaScript事件执行顺序是:事件捕获—>目标阶段—>事件冒泡

 function handleClick(event) {
      event.preventDefault();  //执行完后不再冒泡
      event.stopPropagation(); // 阻止冒泡
      event.stopPropagation(); // 阻止捕获
      console.log("按钮被点击了!");
    }
const myButton = document.getElementById("myButton");
myButton.addEventListener("click", handleClick, {
	capture: false,    // true表示捕获,false表示冒泡  
	once: false,       // 监听器是否只调用一次,调用后自动销毁
	passive: false     // 监听器是否阻止默认操作或停止事件冒泡
});
事件委托

事件处理程序添加到父元素中,而不是在每个子元素上都添加处理程序

优点:内部所有子节点都能使用这个父节点绑定的事件,可以减少内存消耗

问题:只想让部分子节点能触发该事件?父节点绑定一个全新的匿名函数,对当前的目标元素进行角色判断,那么就使用call方法调用真正的事件处理器,并同时修改该函数的this指向

// 假如要给 ul#container 下所有 li 添加点击事件
const container = document.querySelector('ul#container');

// 在 ul 上监听 click 事件,对 li 判断触发事件类型,并且执行事件交互方法
container.addEventListener('click', (event) => {
  if (event.target.tagName === 'LI') {
    // 在这里执行点击交互逻辑,对当前被点中的 li 进行操作
  }
});

10、axios

一般对axios封装,如二次封装fetch方法,进行请求和响应的统一拦截和处理

如:统一处理请求错误,请求时统一携带header头

11、跨域

同源:url 的协议、域名、端口号三者都相同

违反了浏览器的同源策略,就是跨域,跨域报错的目的是为了保证用户的数据安全

如:用户访问B网站,B网站在浏览器后台,使用ajax向A网站发送请求,自动将A网站相关的Cookie携带并发送出去,A网站根据传递过来的Cookie,返回一些用户相关数据,B网站响应数据,获取到了用户的个人信息,他就会通过ajax,再将得到的这些个人信息数据,发送给当前B服务器。这会造成用户数据泄露。

如何解决跨域:

1.JSONP 原理:script标签请求资源,不会报跨域错误的漏洞实现的

function() {
            $.ajax({
                url: 'http://www.liulongbin.top:3006/api/jsonp?name=sy&age=18',
                dataType: 'jsonp',
                success: function(res) {
                    console.log(res);
                }
            })

要注意的是,使用JSONP存在安全风险,因为它要求服务器端返回的脚本代码是可信任的。此外,JSONP只支持GET请求,并且只能进行简单的数据传递,无法处理复杂的请求和响应


2.CORS 原理:只要服务器告知浏览器,愿意被当前网页请求,那么浏览器就不会报错

客户端:当浏览器发出跨域请求时,浏览器会添加一个带有当前源(方案、主机和端口)的 Origin 标头

服务端:响应中添加一个 Access-Control-Allow-Origin,或 * 以允许任何来源

当浏览器看到带有适当 Access-Control-Allow-Origin 标头的响应时,浏览器允许与客户端站点共享响应数据。

在浏览器控制台输入下面命令:

fetch('https://cors-demo.glitch.me/allow-cors', {mode:'cors'})

会看到返回数据允许跨域


3.proxy代理 原理:网页不会直接请求目标服务器,避免跨域操作的出现,

代理除了自带的工具,还可以用第三方如nginx,通过nginx代理服务器,让网页请求接口都处于同源(可解决基本跨域问题)

预检请求

Web 应用程序需要复杂的 HTTP 请求,浏览器会在请求链的前面添加一个预检请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

通常浏览器会在实际请求前,发送一个OPTIONS 

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

服务端会返回以下

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

 12、浏览器输入url到解析的过程

 1、浏览器查看缓存,没有发起新请求,有缓存,检验是否新鲜,足够新鲜直接返回给客户端,否则与服务器交互,通常是Expires 和 Cache-Control控制是否新鲜
2、浏览器解析URL获取协议,主机,端口,路径
3、浏览器封装一个http(GET)请求报文
4、获取主机ip,过程:浏览器缓存->主机缓存->host文件->路由器缓存->DNS缓存->DNS递归查询
5、打开一个socket,与目标地址建立TCP连接,三次握手连接,TCP连接后,发送http请求
6、服务器将响应报⽂通过TCP连接发送回浏览器
7、对响应进行解码(例如gzip压缩),如资源为html文件,解析html文件,构造Dom树,下载资源,构造CSSOM树,执行js脚本,解析过程中遇到图⽚、样式表、js⽂件,启动下载
(解析 html -词法分析然后解析成 dom 树、解 析 css ⽣成 css 规则树、合并成 render 树,然后 layout 、 painting 渲染、复合图 层的合成、 GPU 绘制、外链资源的处理、 loaded 和 DOMContentLoaded 等)
8、JS 引擎解析过程( JS 的解释阶段,预处理阶段,执⾏阶段⽣成执⾏上下⽂, VO ,作 ⽤域链、回收机制等等)

13、网站性能优化

content ⽅⾯ 减少 HTTP 请求:合并⽂件、 CSS 精灵、 inline Image 减少 DNS 查询: DNS 缓存、将资源分布到恰当数量的主机名 减少 DOM 元素数量

Server ⽅⾯ 使⽤ CDN 配置 ETag 对组件使⽤ Gzip 压缩

Cookie ⽅⾯ 减⼩ cookie ⼤⼩

css ⽅⾯ 将样式表放到⻚⾯顶部 不使⽤ CSS 表达式 使⽤ 不使⽤ @import

Javascript ⽅⾯ 将脚本放到⻚⾯底部 将 javascript 和 css 从外部引⼊ 压缩 javascript 和 css 删除不需要的脚本  减少 DOM 访问

图⽚⽅⾯ 优化图⽚:根据实际颜⾊需要选择⾊深、压缩 优化 css 精灵 不要在 HTML 中拉伸图⽚

14、手写发布订阅模式

 封装消息发布订阅组件

export const StorageEmitter = {
  listeners: {},
  // 订阅
  on(event: string, fn: any) {
    ;(this.listeners[event] || (this.listeners[event] = [])).push(fn)
  },
  // 取消订阅
  off(event: string) {
    this.listeners[event] = []
  },
  // 发布
  emit(event: string, ...arg: any[]) {
    this.listeners[event]?.forEach((fn: any) => fn.apply(this, arg))
  }
}

 使用

// 消息发送方
StorageEmitter.emit('标签1的事件');


// 被通知的组件
StorageEmitter.on('标签1的事件', () => {
      fn().then(()=>{
        StorageEmitter.off('标签1的事件');
      })
})

相关资料

总结了17年初到18年初百场前端面试的面试经验(含答案) - 掘金 (juejin.cn)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值