1.大屏的自适应问题
目的使项目内容根据屏幕尺寸变化,并且居中对齐
// 1.监听屏幕的尺寸获得和原先的尺寸比例
// 2.获得左侧和右侧的距离
// 3.通过transform中的translate和scale进行变化
export function autoScale(selector, options) {
const el = document.querySelector(selector)
const { width, height } = options
el.style.transformOrigin = 'top left'
el.style.transition = 'transform0.5s'
function init() {
const scaleX = innerwidth / width
const scaleY = innerHeight / height
const scale = Math.min(scaleX, scaleY)
const left = (innerwidth - width * scale) / 2
const top = (innerHeight - height * scale) / 2
el.style.transform = ` translate(${left}px, ${top}px)scale(${scale})`
}
}
2.如何实现token无感刷新
思路:
简单说就是当短token失效时利用长token去获取短token实现无感刷新的效果
1.在响应拦截器中监听响应码401时调用长token接口获得短token并储存本地中
2.重新调用原接口
要注意的细节点:
1.当 refresh token 也过期的这种情况,会造成死循环,所以可以在请求头中引入一个变量标志进而判断是否是refresh token过期还是 access token过期
2.当refresh token请求失败时,需要走重新登录的逻辑
3.并发刷新 token的情况,多个请求并发且accesstoken刚好失效,这时会造成冗余发送请求,解决方法是实例化一个全局变量的promise,如果其他的请求进来就返回这个promise,最后利用promise上的finally将promise赋值null
3.js的事件循环机制(EventLoop)
学习地址https://blog.csdn.net/snowball_li/article/details/125236024
JavaScript 是单线程语言,这意味着它在同一时间只能执行一个任务。为了实现异步操作,JavaScript 使用了事件循环机制。
js事件循环机制是指js在处理各种事件(例如用户交互、网络请求、定时器等)时,如何协调执行这些事件的机制。JavaScript 事件循环机制分为JS执行栈和任务队列两部分。
JS调用栈是一种后进先出的数据结构,当函数被调用时,会被添加到栈中的顶部,执行完成之后就从栈顶部移出该函数,直到栈内被清空。任务队列是先进先出的数据结构,当主线程空闲时,就会去任务队列中按照顺序读取一个任务放入到栈中执行。
在JavaScript事件循环机制中,任务分为宏任务和微任务。
宏任务包括setTimeout、setInterval、setInterval、NodeJs读取文件I/O操作等;
微任务包括Promise的then
、catch
、finally
回调、MutationObserver、Node 中process.nextTick等。
在每次事件循环开始时,JavaScript会先执行所有的微任务队列中的任务,然后再执行宏任务队列中的任务(promise是同步任务)
事件循环机制是指:
1、代码执行时,先执行同步任务,然后将异步任务放入任务队列中,等待执行。
2、当所有同步任务执行完毕后,JavaScript引擎会去读取任务队列中的任务。
3、将队列中的第一个微任务压入执行栈中执行,所有微任务执行完毕后将其出栈如果产生宏任务则放入宏任务队列中。
4、执行宏任务
5、如此循环执行,直到任务队列中的所有任务都执行完毕。
这就是JavaScript实现异步的基本原理,通过将异步任务放到任务队列中,并通过事件循环机制来实现异步执行。
console.log('start')
setTimeout(() => {
console.log('timeout1')
Promise.resolve().then(() => console.log('then2'))
}, 0)
new Promise((resolve) => {
console.log('promise1')
resolve()
}).then(() => {
console.log('then1')
setTimeout(() => {
console.log('timeout2')
}, 0)
})
console.log('end')
答案:start, promise1, end, then1, timeout1, then2, timeout2
解析:同样的,Promise对象和.then()方法是同步执行的,但是回调函数中包含的Promise对象和.then()方法时异步执行的,会被放到任务队列中等待执行。因此start, promise1, end, then1会先输出。然后在任务队列中执行setTimeout中的回调函数,输出timeout1,然后将包含的Promise对象和.then()方法放到任务队列中。在任务队列中执行.then()方法,输出then2。最后在任务队列中执行第二个setTimeout中的回调函数,输出timeout2。
4.vue中$nextTick的原理
定义:在下次 DOM 更新循环结束之后执行延迟回调。
原理:当数据在发现变化的时候,vue
并不会立刻去更新 Dom
。而是将修改数据的操作放在一个异步操作队列中。如果我们一直修改相同数据,异步操作队列还会进行去重。等待同一 事件循环 中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新。
5.vue2中的data为什么要是个函数
vue中的data写成函数是为了确保每个组件实例都拥有独立的数据副本,避免数据共享和相互影响的问题。
在Vue中,组件是设计为可复用的单元,这意味着它们可能会被多次使用。如果data直接被定义为一个对象,那么所有的组件实例将会共享同一个data对象。这样,当某个实例修改了data中的数据时,其他所有实例中的数据也会受到影响,导致不可预测的行为和bug。
为了解决这个问题,Vue的设计者们将data选项设计为函数。当组件被创建时,Vue会调用这个函数,并返回一个新的数据对象。这样,每个组件实例都会拥有自己独立的数据副本,互不干扰。具体来说,当Vue创建组件实例时,它会在初始化过程中调用data函数,并将返回的对象作为组件实例的data属性。这样,在组件中可以通过this.data
或this.$data
来访问和修改这些数据。
使用函数形式的data选项还有其他好处。例如,函数内部可以进行一些额外的逻辑处理,比如计算属性、方法、监听器等,使得数据管理更加灵活和可扩展。此外,函数形式的data选项还可以接收组件的props作为参数,从而实现更高级的数据初始化逻辑。
总之,将data选项定义为一个函数是为了保证每个Vue组件实例都拥有独立的数据副本,避免数据共享和相互影响的问题,并且提供了更多灵活性和扩展性。
6.前端如何处理跨域问题
一、什么是跨域
跨域也称为非同源策略请求,就是去非同源地址获取数据的行为
只要页面,向非同源地址,发出了ajax / fetch请求,此时就出现了跨域问题。
专业的解释是,两个不同源的服务去访问对方的资源,就是所谓的跨域,而浏览器处于安全方面的考虑是不允许跨域请求的
二、什么是同源
同源是指协议、域名、端口都相同,其中有一个不同就是非同源
解决办法
1.通过jsonp实现跨域
缺点:1.只能发送get请求
优点:支持老的IE浏览器、适合加载不同域名的js、css,img等静态资源
2. 跨域资源共享(CORS)
1.普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置
2.若要带cookie请求:前后端都需要设置。(而且一定要把接口写成域名形式的,不然cookie还是带不上的 测试的的时候我改了hosts文件)
两种请求
一种是简单请求(get,post)
另一种是非简单请求(put,delete) (这个会请求两次)
非简单请求
会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求。
"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的
服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应
3.nginx代理跨域
都是搭建一个服务器,直接在服务器端请求HTTP接口,这适合前后端分离的前端项目调后端接口
4.postMessage跨域
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.) 多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
d.) 上面三个场景的跨域数据传递
用法:postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
5.WebSocket协议跨域
6.nodejs中间件代理跨域
node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发。
7. window.name + iframe跨域
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在
8.location.hash + iframe 跨域
9.document.domain+iframe
适合主域名相同,子域名不同的跨域请求
7.浏览器的回流与重绘
参考地址https://blog.csdn.net/snowball_li/article/details/123280534
一、从上面这个图上,我们可以看到,浏览器渲染过程如下
1、解析HTML,生成DOM树,解析CSS,生成CSSOM树
2、将DOM树和CSSOM树结合,生成渲染树(Render Tree)
3、Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置、大小)
4、Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
5、Display:将像素发送给GPU,展示在页面上。
二、什么是回流重绘
回流:当render tree中元素因为布局或者几何属性发生变化需要重新构建时,这个过程称之为回流。
重绘:当render tree中元素不因为布局或者几何属性发生变化仅仅只是外观样式发生变化需要更新元素,这个过程称之为重绘。
三、重绘与回流的区别
回流必将引起重绘,而重绘不一定会引起回流。
比如:只有颜色改变的时候就只会发生重绘而不会引起回流
当页面布局和几何属性改变时就需要回流。
比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变。
四、会触发重绘或回流/重排的操作
1、添加、删除元素(回流+重绘)
2、隐藏元素,display:none(回流+重绘),visibility:hidden(只重绘,不回流)
3、移动元素,如改变top、left或移动元素到另外1个父元素中(重绘+回流)
4、改变浏览器大小(回流+重绘)
5、改变浏览器的字体大小(回流+重绘)
8.前端性能优化
前端性能着重考虑的两方面
1.首屏时间、和白屏时间
2.操作速度以及渲染速度
优化方式:
a.异步加载,适合体积比较大,又不是马上需要的功能,比如图片压缩功能的第三方库,只有在图片上传的时候才会用到
b.将库的版本更新,因为有些老的库不支持打包工具的tree-shaking,只把用了的方法打包进去,打包体积会减小
c.能不用第三方库就不用第三方库,自己写体积最小
d.骨架屏、loadiing遮罩等操作
e.页面数据比较多的话可以分批滚动渲染
f.减少操作dom
多用v-show少用v-if、循环的时候加好key值、子组件需要的时候可以用keep-alive缓存