前端进阶面试

1 async、await的实现原理?与generator的区别

本文仅供自己参考,本题所有内容来自于掘金大佬:https://juejin.cn/post/7007031572238958629

async/await的用处就是:用同步方式,执行异步操作

注意:await只能在async函数中使用,await后面必须接promise函数,否则会同步输出

async函数执行完会返回一个状态为fulfilled的promise,但是值为undefined

function fn(nums){
 return new  Promise(resolve=>{
 	setTimeout(()=>{
    	resolve(nums*2)
    },1000)
 })
}

function *gen(){
	const num1=yield fn(1)
	const num2=yield fn(num1)
	const num3=yield fn(num2)
	return num3
}

function generatorToAsync(generatorFn){
	return function(){
		const gen=generatorFn.apply(this,arguments)
  		return new Promise((resolve,reject)=>{
  			function go(key,arg){
				let res
				try{
 					res=gen[key](arg)
 				}catch(error){
					return reject(error)	
				}
				const {value,done}=res
				if(done){
					return resolve(value)	
				}else{
					return Promise.resolve(value).then(val=>go('next',val),err=>go('throw',err))
				}
			}
			go('next')
 		})
	}
}

cosnt asyncFn=generatorToAsync(gen)
asyncFn().then(res=>console.log(res))

区别:

  • async时generator的一个语法糖
  • generator执行需要使用执行器(即next方法),async函数自带执行器
  • generator的yield后面可以跟函数或promise对象,而async函数中await后面可以是promise对象或原始值类型

generator如何实现堵塞进程
generator实现了协程,一个进程有多个线程,一个线程有多个协程,但是一个线程只能有一个协程在运行,如果当前协程可以执行,就执行它,否则就将它挂起,然后去执行其他协程,等这个协程结果返回可以继续执行时再来执行它。

2 css in js是什么?css原子性是什么?

就是将css样式写在js文件中,让组件更具可移植性,降低耦合度

比如说:文本超出长度用省略号代替、hover样式更改

css原子性就是定义一个类完成单独的样式功能

3 服务端推送可以怎么实现?

http2.0的服务端推送是指服务器还没有收到浏览器的请求,服务器就主动推送各种资源给浏览器。明显http2.0的服务端推送只是把一些需要的静态资源提前发送给了浏览器,并不适用于推送动态数据的场景。

Server-Sent Events是什么?

服务器发送事件,严格来说,http协议是没有办法做到服务器主动推送信息的,但是当服务器向客户端声明接下来要发送的是流信息,也就是发送的不是一次性数据包,而是一个数据流,这时客户端不会关闭连接,会一直等服务器发送过来的新的数据流

Websocket

websocket是可以在单个tcp连接上进行全双工通信的协议,允许服务端主动向客户端推送数据,它基于http/1.1的101状态码进行握手

  • 他和http协议一样属于应用层协议,默认端口为80/443
  • http请求有同源限制,而websocket没有
  • 协议表示符为ws,可以发送文本,也可以发送二进制数据

websocket和sse的区别

  1. sse使用http协议,websocket是一个独立的协议
  2. sse属于轻量级,使用简单,websocket协议相对复杂
  3. sse支持断线重连,websocket需要自己实现
  4. sse一般用于传送文本,二进制数据需要编码后发送,websocket默认支持传送二进制数据

websocket优化(心跳检测和断开重连)

需要重连的场景可分为三种:
1、连接断开了
2、连接没断但不可用
3、连接对端的服务器不可用

感知是否需要重连(心跳检测):客户端定时向服务端发送心跳信号,如果在一定时间内获取到后端信号,则重新计时,否则说明连接断开,此时客户端就要主动重连

4 计算属性如何传参?

可写计算属性

const a=computed(({
	get:()=>count.value+1,
	set:(val)=>count.value+val
})

调试
computed的第二个参数是一个包含onTrack和onTrigger的回调函数对象

const a =computed(()=>count.value+1,{
	onTrack(){},	//count.value被追踪为依赖时触发
	onTrigger(){}	//count.value被更改时触发
})

计算属性传参

computed(()=>{
	return (value)=>{
		count.value=value
	}
})

5 http请求头和响应头有什么东西?

http请求报文由请求行、请求头、空行和请求体组成

请求行包括:请求方法、请求url地址、http协议及版本
请求头包括:

  1. Accept:告诉服务器,客户端支持的数据类型
  2. Referer:客户端通过这个请求头告诉服务端它是从哪个资源来访问服务器的
  3. Accept-language:告诉服务端,客户端支持的语言
  4. User-agent:告诉服务端客户端的软件环境
  5. Content-Type:客户端向服务端发送数据类型
  6. Host:告诉服务端想访问的主机名
  7. Connection:告诉客户端请求完毕是否保持连接
  8. Cache-Control:遵循的缓存机制
  9. Origin:说明请求从哪里发起,仅包括协议和域名
  10. Authorization:当客户端访问受口令保护时,服务端会发送401状态码和www-authenticate响应头,要求客户端使用Authorization来应答

响应头包括:

  • server:告诉浏览器服务器的类型
  • Location:配合302状态码,告诉客户端找谁
  • Refresh:告诉浏览器间隔多长事件刷新一次

6 https握手过程

使用非对称加密交换对称加密的密钥,使用对称加密传输 数据

1、客户端发起https请求,客户端发送支持的加密方法列表和一个“client random”随机字符串
2、服务器收到后,将数字证书、双方支持的加密方法和另一个随机字符串“server random”发送给客户端
3、客户端对服务器发来的证书进行验证,确保对方身份合法
4、客户端向服务端发送另一个随机字符串并用服务端公钥进行加密,服务端收到后用私钥进行解密得到随机字符串
5、客户端和服务端都受到了三个随机字符串,使用加密方法将三个字符串混合生成密钥
6、握手完成,使用对称加密进行通信

如何确保数据不被篡改?如何验证证书?

数字签名:CA机构通过摘要算法生成服务器公钥的摘要,CA机构通过CA私钥和特定的签名算法加密摘要,生成签名,将签名、服务器公钥、使用的签名算法等信息打包放入到数字证书中返回给服务器。

客户端使用CA公钥和声明的签名算法解密签名,得到服务器公钥的摘要,再用摘要算法加密证书中的服务器公钥生成摘要,将得到的摘要内容与上一步得到的摘要内容进行对比,如果一致,则说明证书合法

7 css动画原理?requestAnimationFrame

动画由许多静止的画面组成,以一定的速度连续播放,肉眼因视觉残留产生错觉误以为是活动的画面

为什么使用setTimeout会导致屏幕卡顿、掉帧?

当屏幕刷新频率为16.7ms,而setTimeout时间为10ms执行时,由于更新步调不一致,在下次屏幕刷新前,setTimeout可能已经执行了多次,导致每次setTimeout产生的动画效果可能不一致

requestAnimationFrame

此api的最大优势是由系统来决定回调函数的执行时机,每次绘制之前都会主动调用requestAnimationFrame中的回调函数,因此不会出现丢帧、卡顿

优势
1、使用setTimeout实现动画在页面隐藏或最小化时,仍会在后台执行动画任务,浪费cpu资源。而RAF不同,在页面处于未激活状态下,该页面的屏幕绘制会暂停,当页面被激活时,动画从上次停留位置开始执行
2、函数节流

transform

transform不会触发重绘和回流,因为transform动画由GPU控制,支持硬件加速,不需要软件渲染

8 如何用map实现深浅拷贝

function deepClone(source){
	if(typeof source!=='object'){
		return source
	}
	if(source==null){
		return source
	}
	if(source instanceof Date){
		return new Date(source)	
	}
	if(source instanceof RegExp){
		return new RegExp(source)
	}
	let res
	if(Array.isArray(source)){
		res=[]
		source.forEach(item=>{
			res.push(deepClonoe(item))	
		})	
	}
	else{
		res={}
		const keys=[...Reflect.ownKeys(source)]
		keys.forEach(key=>{
			let item=source[key]
			res[key]=deepClone(item)	
		})
	}
	return res
}

问题:当存在相互引用时,会出现递归的现象

function deepClone(source,map=new WeakMap()){
	if(typeof source!=='object'){
		return source
	}
	if(source==null){
		return source
	}
	if(source instanceof Date){
		return new Date(source)	
	}
	if(source instanceof RegExp){
		return new RegExp(source)
	}
	if(map.get(source)){
		return map.get(source)	
	}
	let res=Arrar.isArray(source)?[]:{}
	map.set(source,res)
	for(let key in source){
		if(Object.prototype.hasOwnProperty.call(source,key)){
			res[key]=deepClone(source[key],map)	
		}
	}
	return res
}

9 作用域有哪些

  1. 全局作用域
a=1
console.log(window.a)	//1
console.log(delete window.a)	//true
console.log(window.a)	//undefined

var a=1
console.log(window.a)	//1
console.log(delete window.a)	//false
console.log(window.a)	//1

区别在于delete不能删除使用var声明的变量

ECMAScript中有两种属性:数据属性访问器属性

1、configurable:表示能否使用delete删除或能否修改为访问器属性
2、Enumberable:能否通过for-in循环返回属性
3、Writable:表示是否可以修改属性的值
4、Value:包含该属性的数据值

要修改属性的默认特征可以使用Object.defineProperty方法,不能同时声明writable、value和set、get

  1. 函数作用域
  2. 块级作用域:let、const

10 原生js如何获取页面上的节点

  • document.getElementById()
  • document.getElementByClassName()
  • document.getElementsByTagName()
  • document.querySelector()

11 vue2中的mounted钩子在vue3中如何实现的?

vue2使用挂载元素的outerHtml作为template,并替换元素,vue3使用挂载元素的innerHTML作为template,并且只替换挂载元素的子元素

12 http请求行格式

请求方法 请求url地址 http协议及版本

13 多页面和单页面的区别?

单页面应用:一个项目只有一个完整的html页面,页面的跳转通过局部刷新实现,不会重新加载全部资源
多页面应用:一个项目包含多个html页面,页面之间的跳转需要重新加载资源

单页面应用的缺点
(1)首屏渲染时间长

(2)不利于SEO优化

14 vue-router的原理

更新视图但不重新请求页面,vue-router有两种模式:hash和history

(1)hash模式
hash虽然出现在url中,但是不会被包括在http请求中,因此该hash不会重载页面,每改变一次hash都会在浏览器的访问记录中添加一个记录

(2)history模式
主要依赖于pushState、replaceState来操作浏览器历史记录栈,调用这两个方法修改历史信息,虽然改变了url,但是浏览器不会立即发送请求该url

hash模式和history模式的区别:
1、history是利用浏览历史记录栈的 API实现,hash是监听location对象hash值的改变来实现
2、相同的url,history会触发添加到浏览器历史记录栈中,hash不会
3、在history模式下,如果服务器中没有相应的响应或者资源,会出现404错误

15 vuex刷新时数据会不会丢失?刷新丢失怎么处理?

因为js的数据都是保存在浏览器的堆栈内存里面的,刷新浏览器页面,以前堆栈申请的内存就被释放

处理办法:

页面刷新的时候异步请求后台数据,然后动态更新vuex中的数据。但是当网络延迟、数据量大时,还没有等vuex获取到后台返回的数据,页面就已经加载完成了,这样就会造成数据丢失。

监听浏览器刷新前事件onbeforeunload,在浏览器刷新前将vuex数据保存在sessionStorage中,刷新成功后,如果异步请求数据还没有返回直接获取sessionStorage中的数据,否则回去vuex中数据

16 mutations和actions的区别

mutations在请求数据是同步的,而actions是异步的

mutations是同步的意思就是每一个mutations执行完成后都可以对应一个新的状态,这样devtools就可以追踪

actions的参数

context:{
state, //等同于store.$state
rootState,
commit,
dispatch,
getters,
}

17 为什么要使用Proxy和Reflect

通过Proxy创建原始对象的代理对象,从而在代理对象中使用Reflect达到对于js原始操作的拦截

const proxy=new Proxy(parent,{
	get(target,key,receiver){
		console.log(receiver===proxy)	// log:false
		console.log(receiver===obj)		// log:true
		return target[obj]
	}
})

proxy中的get陷阱不仅代表Proxy对象本身,也会代表继承proxy的对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值