前端面试题

html

常用标签

文本,表格,表单,列表等

h1-h6,p,span,label,strong/b,i/em,img,a,div,li,ul,ol,tr,td

 

区分行内元素,行内块级元素,块级元素

行内:同行显示,不支持宽高,span,a,label等;

行内块:同行显示,支持宽高,默认有5px间距,input,img,td,button,select等等

块级:独占一行,支持宽高,h,p,table,tr等

 

如何理解HTML语义化?

根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫更好地解析。 使用语义化标签有诸多好处:

  1. 因为像部分标签自带样式如h1系列,p等,使用语义化的标签可以在样式加载不出的时候有基本样式,而不显混乱

  2. 语义化标签也有利于SEO,语义化标签可以有利于爬虫抓取到网页,因为爬虫依赖于标签来确定上下文和各个关键字的权重。

  3. 语义化标签的实现有利于一些特殊设备的解析,比如盲人阅读器,这为他们浏览网页带来了便利

  4. 语义化标签代码可读性良好,便于代码维护

 

 

css

link和@import异同?

都可以在html中引入css文件

区别:

link是服务于整个网页,@import服务于css

link是一个标签,@import是一种语法

link不只可以引入css文件,还可以引入其他文件格式,@import只能引入文件

加载时间:link加载css文件,随着页面的加载而加载,@import等待页面加载完成之后再加载css文件

兼容性:link兼容比@import要好一些

JavaScript可以操作link引入样式,@import不能被操作。

 

如何让一个盒子在水平方向和垂直方向都居中

通过设置绝对定位和margin自动计算:给四个方向都为0,在配合margin:auto auto;

通过绝对定位:top:50%,left:50% margin top/left 自身宽高的一半;

通过弹性布局:搭配 justify-content 主轴居中 align-item 纵轴居中

 

less或者sass相比于css有什么优势?

支持嵌套

支持变量定义

支持’模板函数(自己定义的名称)’:有些CSS需要做兼容前缀的话,你可以这样使用一个模板函数定义一下,调用的时候传入正常值就可以了。会自动生成前缀的CSS

 

如何做响应式布局或者如何适配

em/rem:em基于父级元素的字体大小,rem基于根标签的字体大小

flex弹性盒模型

媒体查询

使用百分比布局

通过vw/vh来实现自适应

 

css sprite(雪碧图或者精灵图) 有什么优缺点?

将多张图片放在一起构成一张图,从而减少请求服务器次数,来优化网页;

缺点:更改图片时不易更改

 

 

你知道哪些css3新特性和h5新特性

css3:透明度、背景图片、阴影、动画、圆角、弹性盒模型

html5:语义化标签:header,footer,nav etc.、canvas 画布、audio, video、drag 拖拽、本地存储 localStorage, sessionStorage、webSocket 长连接、定位、增强型表单 input number, datalist, keygen, output, progress、svg 矢量绘图、webWorker 实现js多进程。

 

rgba()和opacity的透明效果有什么不同

rgba() 和 opacity 都能实现透明效果,但最⼤的不同是 opacity 作⽤于元素,以及元

素内的所有html标签及文本的透明度,

⽽ rgba() 只作⽤于元素的颜⾊或其背景⾊。(设置 rgba 透明的元素的⼦元素不会继承

透明效果!)

js

js数据类型有哪些?有什么区别

引用类型:object 数据存放在堆中,栈中存放指针指向堆中的数据

其他都是基本数据类型

number,string,object,undefined,boolean,null,symbol,BigInt

 

谈一下你对作用域的理解

作用域指在运行代码中的某些特定部分中变量,函数和对象的可访问的范围

主要分为全局作用域,函数作用域和块级作用域

全局作用于全局,在代码任何地方都能够访问到;

函数作用域指在函数内部的变量,只作用域函数内部;

块级作用域指lethe const声明,所声明的变量在指定块的作用域外无法被访问;

 

谈一下你对原型的理解

原型:构造函数的prototype.constructor指向自身,每个实例对象(object)都有一个私有属性(称之为proto)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为null。根据定义,null没有原型,并作为这个原型链中的最后一个环节。

原型链:对象在访问某个属性时,会现在本对象上找,如果没有找到,则去对应的原型里找,找到了直接使用,如果还没找到,如果原型对象上还有原型,那么会继续往上一层原型对象中查找,直到原型对象为object类为止,如果到object类还没找到,则返回undefined

 

什么是闭包

闭包就是能够读取其他函数内部变量的函数;

嵌套的内部函数,包含被引用变量(函数)的对象;

优点:闭包会延长变量的声明周期;缺点:会造成内存占用

 

如何修改函数的this指向,这些方法之间有什么区别?

三个方法:call,apply,bind

三个功能相同,区别在于参数的不同或是否立即调用:

call和apply之间唯一区别就是传参的不同。第一个参数仍都是指的执行对象,call方法从第二个参数开始,会将后续的参数当成函数所需的数据。而apply则吧函数所需的数据都放在数组里面,数组作为apply方法的第二个参数。(apply传递参数需要使用数组包裹);

call和bind之间的区别是call是立即调用所需的函数,只能调用一次。而bind参数跟call是一样的,不过bind不会马上执行,而是将所需要的函数给返回,这样就可以重复的使用所需的函数(apply,call会立即执行一次,bind是创建一个新函数,不会立即执行)

bind只生效一次。

理解=>前两个会立即执行,bind返回一个新的函数,并指向参数

 

事件委托或者事件代理的原理是什么?

事件委托是利用事件冒泡原理实现的,给父级或祖先标签设置一个事件处理程序,然后利用event对象里的target来判断实际触发事件的标签,然后调用对应的处理代码

 

事件冒泡和事件捕获的区别是什么?

冒泡:执行一次完整的冒泡,即从具体子标签开始触发,直到window对象为止,即从目标节点传导回window对象(从底层传回上层)。

捕获:从window对象触发,一直到具体的子标签为止,即从window对象传导到目标节点(上层传到底层)。

 

你知道的es6新特性有哪些?

let和const,object.keys(),for…of,扩展运算符,set和map,模板字符串,结构赋值,默认参数,rest参数,箭头函数,解构赋值

 

js异步编程方式有几种

回调函数,事件监听,Promise,async/await, generator

 

promise有几种状态

pending fulfilled rejected 当我们创建一个Promise对象的时候,它的状态默认是pending ,要修改它的状态必须调用resolve方法或者reject方法

const myPromiseObj = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve()
    })
})
myPromiseObj.then(()=>{}).catch(()=>{})

 

js如何浅拷贝和深拷贝一个对象

浅拷贝是指复制指向某个对象的指针(地址)而不复制对象本身,新旧对象还是共享同一块内存,修改一个另一个也会改变。

深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

浅拷贝:Object.assign 或者拓展运算符...,concat(),赋值 = slice

深拷贝:const deepCopiedObj = JONS.parse(JSON.stringify(obj))

 

rem和em和px的区别

px是固定单位,rem和em是响应式单位,1rem的大小取决于根节点html的字体大小(即font-size属性),1em的大小取决于其父节点的字体大小,在移动端我们一般用rem,但是要注意:这时html的fontSize属性应该是动态计算的,而不是写死,一般是把当前可视窗口的宽度除以一个经验值得到的比值作为html的fontSize属性值的。

 

for循环中break和continue的区别是什么?

break:跳出整个循环

continue:跳出档次循环,继续执行后面的循环

 

如何用原生js给一个按钮的点击事件绑定两个事件处理函数

addEventListener

 

js引擎如何实现异步的?

js引擎是通过事件循环(Event Loop)实现异步的;js引擎在执行代码的过程中,如果遇到异步任务,则跳过该异步任务,继续执行后面的同步任务,同步任务执行完了,再执行异步代码

 

完整:浏览器是多线程,js引擎只是浏览器的其中一个线程,除此之外,它还有http请求线程,事件处理线程,定时触发线程,GUI渲染线程

js引擎线程:执行js代码

执行栈:所有的js代码都要在执行栈里面执行

任务队列:关于异步任务的回调函数最终都会被放到任务队列中来等待执行 先进先出

异步微任务对列(优先级更高) :promise.then proccess.nextTick

异步宏任务队列 setTimeout setintval

http请求线程:发送http请求

事件触发线程:监听用户事件

定时触发线程:计时

GUI渲染线程:界面的渲染,该线程和js引擎线程是互斥的,两个只能同时执行一个

 

js引擎如何实现异步

当js引擎在执行栈中执行js代码的时候,如果遇到了异步任务(比如发送请求),则js引擎会把该异步任务交给浏览器的其他线程处理(http请求线程)。

js引擎继续之后后面的同步任务,当执行栈中的任务清空之后,js引擎就会到任务队列里面去查找有没有待执行的回调,有的话,就拿到执行栈中去执行,执行完了,又会去任务队列中去查找有没有待执行的回调,有,就拿到执行栈中执行,如此循环往复的过程就是事件循环(Event Loop),理解了事件循环就相当于理解js引擎如何实现异步。

其他线程(http请求线程)也在同时的工作,当其他线程把异步处理完了(http请求线程接口发送成功)之后,它会把我们设置的回调函数推送到js引擎的任务队列里

 

什么是事件循环??

js引擎里面有两个非常重要的部分:执行栈和任务队列

所有的代码都要加载到执行栈里面进行执行

在执行过程中如果发现有异步任务,则js引擎会把这个异步任务交给浏览器的其他线程去处理,比如在执行的时候遇到

接口发送,则js引擎会把它交给http请求线程去处理,然后js引擎继续执行后边的同步任务,但是同http请求线程也在同时

运作,当请求发送成功之后,即数据拿到之后,http请求线程会将我们之前在js里面设置的回调函数推送到js引擎的任务队列里面

当js引擎在执行栈里面把任务清空之后,则回到任务队列里面去寻找有没有待执行的回调函数,有则拿到执行栈里面去执行

执行完了之后,又会到任务队列里面去寻找有没有待执行的回调,如此循环往复的过程就是事件循环,理解了事件循环就理解了

  * 浏览器是多线程的,js引擎只是其中一个线程,除此之外还有http请求线程,定时触发线程,事件处理线程,GUI渲染线程

 

什么是函数柯理化?

 

通过函数返回函数的方式(闭包),让一个一次性接受多个参数的函数,分解为一次只接受一个参数的若干函数的组合

其作用是为了参数的复用,

 

函数柯理化:把原本会一次性接收多个参数的函数,利用闭包的形式变成一次只会接收一个参数的多个函数;

作用:复用参数

 

function towSum(a,b){
    return a + b;
}
​
//现在对上面的函数进行柯理化
function towSum(a){
    return function(b){
        return a + b;
    }
}
​
或者
const res = (a)=>(b)=>a+b;
​
​
调用:
towSum(1)(2);
或者
const res = towSum(1)(2);
res(3)
​

 

 

微任务和宏任务的区别
DOMContentLoaded和load事件的区别

 

防抖和节流有什么区别,如何实现

在高频触发的事件中,可能会导致一些性能问题,比如在PC端浏览器缩放时(resize事件),我们在事件处理函数里面如果操作DOM,则用户缩放的时候,可能会导致浏览器卡顿,这是我们就可以通过防抖节流来控制操作DOM的频率,避免过快的操作DOM,但是这两者的区别在于:

防抖的思路是:设置一个延时器,延时n秒在执行相应的逻辑(即频繁执行可能会影响性能的逻辑),如果在n秒内,再次执行了,则清空延时器,并从当下开始从新设置延时器,n秒后再执行。

节流的思路是:在特定的时间段内,相应的逻辑必须有且只能执行一次。

 

//防抖
function debunce(func,time){
    let timer = null;
    return function(){
        if(timer)clearInterval(timer);
        timer = setTimeout(()=>{
            func.apply(this,arguments)
        },time);
    }
}
//节流
function throttle(func,time){
    let preTime = +new Date()  //上一次执行的时间戳
    return function(){
        const curTime = +new Date() //本次执行的时间戳
        if(curTime - preTime >= time){  //对比当前执行时间和之前执行时间 是否大于time秒 大于则执行func的逻辑
            func.apply(this,arguments);
            preTime = curTime;
        }
    }
}

 

 

代码题
var a = {};
var b = {key:"b"};
var c = {key:"c"};
a[b] = "b";
a[c] = "c";
console.log("a[b]",a[b]);//???

 

  1.  

    var age = 100;
    let years = 6;
    if(age > 12){
        let age = 10;
        var years = age*3;
    }
    //问:以上代码有问题吗?

     

  2.  

    componentDidMount() {
            this.setState({ count: this.state.count + 1 });
            console.log('1', this.state.count);
            this.setState({ count: this.state.count + 1 });
            console.log('2', this.state.count);
            setTimeout(() => {
                this.setState({ count: this.state.count + 1 });
                console.log('3', this.state.count);
                this.setState({ count: this.state.count + 1 });
                console.log('4', this.state.count);
            }, 0);
    ​
        }
        
        //打印结果
        

     

  3.  

    function Cat() {
               let showName = function () {
                    console.log(1);
                }
                return this;
     }
           
            Cat.showName = function () { console.log(2) };
            Cat.prototype.showName = function () { console.log(3) };
            var showName = function () { console.log(4) };
            function showName() { console.log(5) };
            Cat.showName();
            showName();
            Cat().showName();
            showName();
            new Cat.showName();
            new Cat().showName();
            new new Cat().showName();
            //打印结果??

     

  4.  

    function Cat() {
               showName = function () {
                    console.log(1);
                }
                console.log('this',this)
                return this;
               
     }
           
            Cat.showName = function () { console.log(2) };
            Cat.prototype.showName = function () { console.log(3) };
            var showName = function () { console.log(4) };
            function showName() { console.log(5) };
            Cat.showName();
            showName();
            Cat().showName();
            showName();
            new Cat.showName();
            new Cat().showName();
            new new Cat().showName();
            
            //打印结果,注意跟上一题的区别

     

  5. 这段代码有什么问题吗?

    this.setState((state,props)=>{
        return {total:state.total + props.count}
    });

     

  6. 查看一下代码:如果你在页面中创建了一个React元素,请完成他的组件定义?

    <Profile username="sofn">
        {user=>user===null ? <Loading/> : <Badge info={user}/>}{" "}
    </Profile>
    ​
    import React ,{Component} from 'react';
    import PropTypes from 'prop-types';
    import fetchUser from 'utils';
    //fetchUser接收用户名,并返回promise
    //当得到用户数据的时候返回resolve状态
    class Profile extends Component{
        //在这里写下你的代码
        
    }

     

     

 

 

vue

vue组件中watch和computed的区别
1. watch中一个值的变化可能会引起多个值的变化,而compouted中多个值的变化会只会影响一个值的变化(即该计算属性返回的值)
  1. 在watch中我们可能会有副作用,比如发送请求等,而computed则没有副作用,仅仅是根据母体数据衍生出新的数据而已。

vue常用的生命周期钩子函数有哪些?分别有什么作用?

 

钩子函数 created mounted updated beforeDestory
执行时机 数据初始化完毕之后 DOM渲染完毕之后 数据更新完毕并且DOM更新完毕之后 组件卸载之前
作用 发送请求 发送请求、获取DOM等 发送请求(注意加上条件判断)、获取DOM等 性能优化相关,比如清除定时器、延时器、解绑事件等

 

 

vue如何实现组件通信(组件传值)? 父子 兄弟 复杂组件关系

 

组件关系 父子 兄弟 复杂组件关系
通信方式 props/绑定自定义事件、$emit 状态提升、事件总线 状态机vuex

 

 

vue项目如何做路由拦截?

全局路由守卫(router.beforeEach)、局部(页面内部)路由守卫

vue的响应式原理 Object.defineProperty

vue组件中data里面的数据,在初始渲染之前都会被Object.defineProperty转化成响应式数据,然后这些数据的访问和修改就能够被监听了,每当数据被访问的时候就会触发getter,接着会通知watcher,watcher这是会做一次依赖的收集或者更新,然后watcher会负责通知渲染界面(先转化为虚拟DOM,在映射为真正的DOM)。每当数据被设置的时候会触发setter,接着setter也会通知watcher,watcher在去通知渲染界面

 

作用:生成响应式的数据,即通过该方法设置过的属性,它的设置和获取都能够被监听

let o = {
    name = '张三'
}
let _name = o.name;//赋值  方便访问o.name
object.defieProperty(o,'name,{
get:function() {
console.log('get函数执行了')
return _name 
},
set:function(val) {
console.log('set函数执行了',val)
 _name = val  //在get和set里面不能使用name 因为用了name就是会去get里面访问 然后又去访问 死循环了
}
}')
o.name = '王二麻子'
console.log(o.name) // 王二麻子

 

 

v-if和v-show的区别

v-if 操作节点 性能消耗高

v-show 操作样式

v-if和v-for能一起用吗

v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中

理论上是可以的 但是性能消耗高 不推荐

keep-alive组件有什么作用

缓存组件 注意它的两个钩子函数

this.$nextTick有什么作用

类似updated,你可以称作移动版的updated,如果你想获取数据更新过后,DOM的最新状态,则可以使用该方法(如果你直接获取DOM状态是拿不到的,因为在vue里面数据更新虽然是同步的,但是DOM的更新是异步的),当然你也可以利用updated生命周期钩子函数,但是不方便

this.$set有什么作用

在组件data中预定义的数据,一定是响应式的,但是我们后续,通过常规的方式(比如someObject.propName = xxx)为data中某些对象添加新的属性时,这些新的属性并不是响应式的,这是可以使用该方法。 this.$set(target,prop,value) 这里的prop属性就是响应式的

vuex核心概念

state 数据源,载体 getters 用于改变state的值,派生出多个数据源 mutation 唯一可以提交可以改变state的状态,也就是数据的属性值 actions 提交的是mutation,用commit提交 而不是直接变更状态,可以包含任意异步出操作 modules 拆分成多个模块

vue如何做路由懒加载

路由配置中component属性的值修改为:()=>import(组件路径)

你认为vue 框架和jquery有什么区别?

开发思想不同,vue是数据驱动,并且可以组件化开发,jquery则是DOM驱动的,开发效率低

vue如何自定义指令
如何封装一个vue插件
什么是过滤器(filter)
vue中extends的用法
vue如何提取组件的公共逻辑

vuex/mixins/自定义指令/插件

 

react

shouldComponentUpdate有什么作用?

它是react组件的一个 生命周期钩子函数,每次数据更新时,首先会执行该钩子函数,如果返回true,表示可以更新界面,然后后续的钩子函数才会陆续执行,返回false,则表示不可以更新,后续的钩子函数也不会执行,当然它默认返回true,

我们一般不会直接在组件中使用该钩子函数,而是会选择PureCompopnent来代替Component,在PureComponent里面就利用来该钩子函数来做优化

setState有什么特性

它的作用是更新组件内部状态,可以接受两个参数,参数一个一般是个对象,在底层react会通过Object.assign把传入的对象和原来的state进行合并,当然也可以传入一个函数,这个函数会接受两个形参(一个表示state,一个表示props),并返回个对象,要注意的是,这个函数在执行是会保证之前的state已经更新完毕,最后在把该函数返回的对象和原来的对象进行合并。当新的状态值会基于老的状态值时,我们会倾向于给setState的第一个参数传递一个函数进去。它的第二个参数则是一个回调函数,会在数据更新完毕,并且dom更新完毕时执行。

另外,当我们在react事件体系或者组件生命周期钩子函数里面直接调用setState的时候,它是异步的,其他情况是同步的,比如在setTimeout/setInterval里面调用就是同步的

this.setState({name:'张三'});
this.setState((state,props)=>({})

 

 

react列表渲染时,key的作用

提升渲染性能

react组件之间如何通信

父子(props)、兄弟(状态提升、事件总线)、复杂组件关系(状态机)

解释一下redux核心概念

store action reducer

react常用的生命周期钩子函数有哪些?分别有什么作用

 

钩子函数名 constructor render componentDidMount componentDidUpdate componentWillUnmount
执行时机和作用 组件初始化时负责数据的初始化 渲染界面 DOM渲染完毕时执行,可以在这里发送接口,获取DOM等 数据更新完毕且界面更新完毕后执行 组件即将卸载的时候执行,可以在这里清除定时器,延时器,解绑事件等等
           
           

 

react中refs有什么作用?
1. 获取DOM
  1. 获取组件实例

redux中间件是什么,有什么作用,你常用的中间件有哪些?
redux三大原则是什么?
  1. 单一数据源

  2. store中的数据(state)是只读的,唯一修改state的方法就是派发action

  3. 必须通过纯函数reducer来执行修改

react中容器组件和展示组件有什么区别?
函数组件和类组件有什么区别(16.8以前)?
你对react新特性hooks有什么了解吗?
react如何提取组件之间的公共逻辑
什么是高阶组件?有什么作用?你常用的高阶组件有哪些
受控组件和不受控组件有什么区别?
JSX的底层原理是什么?
react组件的数据来源有哪些?他们之间有什么区别?
react插槽是什么?(或者react中如何实现组件复合?)
react中context是什么?
react中废弃了哪些和新增了哪些生命周期钩子函数

小程序

小程序一个页面有几个文件构成?
小程序怎么跟后台交互

(1)直接用微信官方提供的接口 wx.request接口,跟jquery的ajax差不多

小程序怎么做扫码功能(wx.scanCode),怎么做支付功能(wx.requestPayment)

(1)调用微信提供的现成的接口(wx.开头的),即可,具体参数怎么传参照文档即可

微信里面怎么获取用户的手机号??

(1)简单,直接用微信官方提供的现成组件button即可,具体用法是在button上加一个属性opent-type,方它的值为getPhoneNumber,不知道怎么用的去找微信官文档看看、

小程序分包是什么?有什么作用?

提示:跟vue路由懒加载有类似的作用,提升用户体验度,减少首屏渲染速度

//developers.weixin.qq.com/miniprogram/dev/framework/subpackages/basic.html

//blog.csdn.net/acmdown/article/details/80037660

其他

性能优化

从用户在浏览器中输入url,到浏览器渲染出界面,中间发生了什么?

DNS域名解析——》发起http或者https请求——》服务端处理请求——-》浏览器接受请求响应,并渲染界面

SPA(single page application)如何提高首屏(注意:不是首页,一般你在url中输入一个新的路劲,然后回车,即是一个首屏)的渲染速度
DNS域名解析部分优化
  1. DNS prefetch(DNS预解析)

在html头部使用link标签进行DNS预解析
<link rel="dns-prefetch" href="//www.baidu.com">
发起请求部分
  1. 减少请求次数

    1. 采用css sprinte(也叫雪碧图或者精灵图),即:如果有多张比较小的背景图,可以合成一个,然后通过background-position去设置背景,而不用每个都去发送请求

    2. 某些图片编译成可以是用base64格式(webpack中的url-loader会自动把大小小于某些值的图片编译成base64格式的,然后内嵌到js文件中,所以后续在访问这些图片时,不在需要单独发送请求)

      • 何时用base64格式的图片??,可以参考以下几个因素

        1. 这类图片不能与其他图片以CSS Sprite的形式存在,只能独行

        2. 这类图片从诞生之日起,基本上很少被更新

        3. 这类图片的实际尺寸很小

        4. 这类图片在网站中大规模使用

    3. 合并脚本和样式表,但是要视情况而定,如果合并脚本或者样式表后,包的体积变得非常大,反而会过度延长网络请求时间,从而导致首先渲染更慢

    4. 利用http缓存(新鲜度限值和服务器在验证)

  2. 减少请求或者服务端响应式时(当然主要是响应),网络数据包的大小

    1. 压缩css/js、图片等

    2. 路由懒加载

  3. 缩短网络的传输距离,优化网络传输路径

    1. 利用CDN(内容分发网络),一般我们会把静态资源,即很少变化,体积有比较大的资源交给CDN服务商管理

 

服务端优化:不需要关注

使用单独的图片服务器、使用redis缓存、使用负载均衡等等

浏览器渲染
  1. css放在body之前,script放在body之后

  2. ssr(server side render—服务端渲染)

  3. requestAnimationFrame

    对于动画来讲:定时器为什么不是一个好的方案

    1. 开发人员并不知道,间隔多少时间出发一个动画何时,间隔时间如果太短,则会损耗浏览器的性能,如果间隔时间太长,则用户就会感觉卡顿。并且定时器自身机制的问题,它的回调函数触发的时机可能并不是你设置的时间,因为他要等到执行栈里面的任务清空之后再去执行

    优化要达到的目的:间隔时间合适,同时用户不会觉得卡

    分析:

    第一:间隔时间要合适,你自己手动设置肯定不行,因为延时器或定时器触发的时机本就不精确。

    第二:用户不会觉得卡顿,首先我们要搞清楚是什么原因导致的卡顿,所以接下来,我们要解释一下浏览器的概念

    帧:浏览器中的页面是有一帧一帧绘制出来的,当每秒钟绘制的帧数(FPS–Frame Per Second)大于或等于60的时候,用户是感觉不到卡顿的,换言每一帧的时间控制在1s/60,也就是大约16.6毫秒之内时,用户是感觉不到卡顿的。

     

    在一帧中浏览器大致做了如下事情(有时不一定每一步都会执行):

    1. 处理用户的交互

    2. js解析执行(例如用户事件处理函数中的逻辑)

    3. 调用window.requestAnimationFrame中注册的函数(注意:这个函数其实是上一帧中注册的函数,且如果在这一帧中发现有注册的函数,则该函数一定会被执行

    4. Layout(布局,如果第二次触发,我们就称之为回流)

    5. Paint(绘制,如果第二次触发我们就称之为重绘)

    6. 如果前五步骤执行完了之后,这一帧还有剩余时间,则调用window.requestIdleCallback中注册的函数

     

    也就是说这前五个步骤(其他我们先暂时不用考虑)执行时间总和要在16.6毫秒内,才能保证用户体验。

    结论:我们可以利用requestAnimationFrame实现动画逻辑,并且不需要传递时间,在这里触发动画,一般情况1秒钟也能达到60帧(当然动画里的逻辑也不能太复杂,在这一步,如果执行时间过长也会导致掉帧(1秒钟没有达到60次),从而让用户决定卡顿),具体用法如下(实现一个元素,在水平方向上左右移动的效果)

    <div style="width:50px;height:50px;" id="myDiv"></div>
     
      let originStep  = 10;   
      let step = 10;//每次移动的距离
      let direction = 1;//移动的方向1表示向右,-1表示向左
      let left = 0;//元素的偏移量
      const offsetWidth = document.body.offsetWidth;//body的宽度
      const el = document.getElementById('myDiv');
      const eleWidth = el.offsetWidth;//元素的宽度
      const runAnimation = () => {
          if(direction === 1){
            const remainOffset = offsetWidth - (left + eleWidth);//向右移动时,距离右边距剩余距离
          if(remainOffset < step && remainOffset !== 0){
            step = remainOffset;//保证向右的移动不会超出右边接线
          }
          }else{
            step = originStep;//当向左移动的时候恢复移动速度
          }
          if(left <=0){
            direction = 1;
          }else if(offsetWidth <= left + eleWidth){
            direction = -1;
          }
          const xOffset = left += step*direction;
          el.style.transform = `translate(${xOffset}px,0)`;
          requestAnimationFrame(runAnimation);//在注册回调
       }
       requestAnimationFrame(runAnimation)

     

     

    • requestAnimationFrame执行过后会返回一个id,跟定时器一样,我们可以根据这个id取消对应的requestAnimationFrame

      const cancelId = requestAnimationFrame(runAnimation);
      cancelAnimationFrame(cancelId);

       

     

  4. requestIdleCallback

 

SSR(Server Side Render)和CSR(Client Side Render)

SSR

浏览器中显示的页面,是由服务器拼接好模板,然后通过网络传送到浏览器,在有浏览器直接渲染的,由于在网络传输路径中携带了网页的内容,所以ssr模式非常适合做SEO,同时服务器拼装模板的速度会比浏览器快很多,所以SSR模式也会提升网站的首屏渲染速度。但是也会增加服务端的压力。

ssr两个优势

利于seo

缩短首屏渲染速度

 

CSR

 

webpack

webpack有什么作用?

什么是webpack ? 模块化的打包工具,原理是,我们必须向它提供一个入口js文件,然后webpack会根据这个入口文件生成一张依赖图,然后在堆这张依赖图里面的文件进行转义和打包,最后生成浏览器能够识别的资源文件(css js 。。。)

作用:

1. 让项目模块化
  1. 编译scss/less .vue jsx

  2. 性能优化:压缩、代码拆分、图片转base64格式。。。

  3. 工程化:自动编译、打包

webpack常用配置项有哪些?(webpack.config.js)
  1. entry:入口文件

  2. output:出口文件

  3. module

    module:{
    rules:[
        {
                test:/\.css$/,
                use:['style-loader','css-loader'],//从后往前执行
            }
        ]
    }

     

     

 

 

网络相关

常用的http状态码有哪些,
1. 200 
  1. 404

  2. 401

  3. 500

  4. 304

  5. 301 资源永久重定向

 

http和https的区别

安全:https协议在传输数据的时候,会对数据进行加密,http则是明文传输

性能:http协议的传输性能更高,因为对于传输同样的数据量来讲,由于https协议需要加密处理,所以最终在线路上它的数据量要大一点

费用:https需要购买证书,http则免费

默认端口不同:https–443 http—80

websokect和http的区别

websokect能够实现客户端和服务端的双向通信,http则只能是单向通信,由客户端去请求服务端,服务端不能主动的向客户端推送数据

应用场景不同

websokect 实时通信 数据的实时更新

http 简单的客户端请求服务端

业务相关

如何处理权限问题

比如后台管理系统,不同的角色看到的侧边栏项是不同的,如何实现?

首先把侧边栏抽象成一个数组,数组里面每一元素(对象)则表示每一个侧边栏,并且在每一个元素里面,我们需要添加一个表示角色的字典,以此来区分,何种角色能够看到当前侧边栏项,

接线来,就要根据当前登录人的角色 去 过滤当前数组,并返回当前角色能看到的侧边栏数据

最后在根据得到的数据,进行遍历循环,渲染侧边栏

前端如何实现身份验证

前端现在一般用token实现身份验证, 登录过后后端会给到前端返回一个token,然后我们把这个token存到本地存储,然后后续在进到主页之后,基本所有的接口发送时,我们都要把这个token添加到header里面,

这时,后端接受到请求之后,会先去解析token,如果能够正常的解析,则表单当前登录人没有问题,可以正常返回数据,否则返回401

数据可视化如何实现(echart)

option setOption(option)

如何实现数据的实时更新 websokect

在项目中如何做到token的无感刷新
uni-app中要路径跳转,如何提高效率

使用uni.preloadPage页面预加载,但是该方法有兼容性问题,只在app端和H5端有效

请说一下你项目中微信支付流程如何做的
说一下项目中微信授权登录的流程。前后端是如何去交互的

参照://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

项目中权限如何如何渲染,如果后端的权限粒度要控制到每个功能如何实现
为什么使用uni-app,你在项目开发的过程中遇到哪些兼容问题,以及如何处理的
  1. 页面预加载,只有H5和APP端支持,小程序不支持

  2. css中给元素设置背景图,H5端支持,小程序不支持(在小程序端用行内样式设置背景图即可)

  3. css中通配符*在H5端支持,但是小程序不支持

  4. 在非H5端不能使用ref的方式引用内置组件(比如view等)

    • 如果想为不同的平台写不同的代码,可以使用条件编译

项目中遇到的最大的问题是什么
在页面中如果要同时发送5个接口,当所有接口都成功相应之后,再去做其他操作,这个如何实现
项目是如何打包上线的,打包的时候需要配置些什么内容
项目中如何实现上拉加载,下拉刷新的,如果要自己实现,说一下思路
前端登录后,传递id给后端获取数据,这种方式安全吗?你是如何来避免的
1. 把get方式换成POST
  1. 如果我用抓包工具,把数据抓下来,在伪装发送接口,怎么办?—–http–>https

项目如何打包为apk,如果是ios系统,如何打包呢
团队中各个成员是如何配合的
微信小程序如何发布上线

 

微信小程序上线发布,通过有上角的上传按钮即可哈,上传后,微信官方会做一个审核,审核通过之后,我们就能够通过微信搜索到该小程序了

浏览器

什么是跨域?如何解决

跨域是浏览器的同源策略导致的问题,当我们的协议、域名和端口号,任意一个不同的时候,就会导致跨域的出现

常见的一个场景,前端请求后端api的时候出现跨域,如何解决?

  1. 前端处理:代理服务器 webpack-dev-server (vue.config.js)


    devServer:{
    proxy:{
    "/api":{
    target:"//localhost:8000"
    }
    }
    }
  2. 后端处理

    1. 设置响应头

浏览器渲染页面的流程

GUI渲染线程负责界面的渲染过程

同时解析html/css

解析html —->DOMTree

解析css—>CSSTree

然后合并DOMTree和CSSTree形成RenderTree(渲染树)

接下来开始layout (布局,回流)

绘制(重绘)

 

根据这些过程我们可以知晓在写html的时候需要注意的一些事项(性能优化)

1. css放在头部
  1. js放在尾部,因为js是有js引擎去编译和执行的,而js引擎和GUI渲染引擎是互斥的

重绘和回流有什么区别

 

 

数据结构相关

你知道的数据结构有哪些?

栈、队列、链表、二叉树

空间复杂度和时间复杂度

这个两个概念是用来衡量一个算法优劣的两个维度,空间复杂度表示,算法所消耗的内存大小,而时间复杂度,表示一个算法所消耗的时间。一般情况下,我们更看重一个算法在时间上的消耗。如果时间太长,则认为这个算法是不太好的需要优化,所以才会有用空间换时间这个说法。

时间复杂度可以用大O表示法。