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的区别:
- sse使用http协议,websocket是一个独立的协议
- sse属于轻量级,使用简单,websocket协议相对复杂
- sse支持断线重连,websocket需要自己实现
- 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协议及版本
请求头包括:
- Accept:告诉服务器,客户端支持的数据类型
- Referer:客户端通过这个请求头告诉服务端它是从哪个资源来访问服务器的
- Accept-language:告诉服务端,客户端支持的语言
- User-agent:告诉服务端客户端的软件环境
- Content-Type:客户端向服务端发送数据类型
- Host:告诉服务端想访问的主机名
- Connection:告诉客户端请求完毕是否保持连接
- Cache-Control:遵循的缓存机制
- Origin:说明请求从哪里发起,仅包括协议和域名
- 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 作用域有哪些
- 全局作用域
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
- 函数作用域
- 块级作用域: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的对象