·h5和css3的认知
CSS3
1、强大的选择器
2、圆角效果
3、块阴影和文字阴影
4、色彩:CSS3支持更多的颜色和更广泛的颜色定义
5、渐变效果
6、个性化字体:@Font-Face
7、多背景图
8、边框背景图
9、变形处理:可以对HTML元素进行旋转、缩放、倾斜、移动以及动画
10、多栏布局
11、媒体查询:不同屏幕分辨率,应用不同的样式
·data-v-03da18b4
这是在标记vue文件中css时使用scoped标记产生的,因为要保证各文件中的css不相互影响,给每个component都做了唯一的标记,所以每引入一个component就会出现一个新的’data-v-xxx’标记
·http部分
http和https区别
- Https协议需要ca证书,费用较高。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- 使用不同的链接方式,端口也不同,一般而言,http协议的端口为80,https的端口为443
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
浏览器与访问服务器之间会完成一次http请求,步骤如下:
1.DNS域名解析为服务器主机的IP地址;
2.根据IP,找到对应的服务器,发起TCP三次握手;
3.建立TCP连接后发起HTTP请求;
4.服务器得到HTTP请求,浏览器得到HTML代码;
5.浏览器解析HTML代码,并请求HTML代码中的资源(如js,图片,css,先得到代码才能去找这些资源);
6.浏览器对页面进行渲染并展示给用户;
那么最后一步浏览器是如何对页面进行渲染的?
a)解析html文件构成 DOM树;
b)解析CSS文件构成渲染树;
c)边解析,边渲染 ;
d)JS 单线程运行,JS有可能修改DOM结构,意味着JS执行完成前,后续所有资源的下载是没有必要的,所以JS是单线程,会阻塞后续资源下载;
前端HTTP优化
1、合并、压缩、混淆
文件合并,减少 http 请求次数
压缩、混淆,减少静态资源大小
实现上,可使用 webpack 配合系列插件,打包过程中可压缩源代码(去空格、换行、注释,JS混淆代码等等)
2、 http gzip 压缩
减少 http 传输过程中文件大小
3 Not Modified 304
减少传输内容提升性能。
客户端有缓冲的文档并发出了一个条件性的请求。服务器告诉客户端,原来缓冲的文档还可以继续使用,涉及以下两种 HTTP Header。
4 浏览器缓存
Last-Modified 和 Etag 标识资源变化情况,服务器返回 304 Not Modified 降低网络传输大小,提升性能。但是对于如图片、react/vue这类库资源、通用css这些不经常变化的静态资源,应利用浏览器缓存功能,连304这次请求都优化掉
·网页有哪些部分
结构层:由html或XHTML的标记语言负责创建。标签,就是那些出现在尖括号里的单词,对网页内容的语义含义
做出了描述,但这些标签不包含任何关于如何显示有关内容的信息。例如,p标签表达了这样一种语义:“这是
一个文本段”。
表示层:由CSS负责创建。CSS对“如何显示有关内容”的问题做出了回答。
行为层:负责回答“内容应该如何对事件做出反应”这一问题。这是JavaScript语言和DOM主宰的领域。
·服务器渲染
服务器渲染(后端渲染)
浏览器发送请求到服务器端,服务器端处理请求并处理好数据,然后生成html文件,并返回给浏览器。
传统的jsp、php都是属于服务器渲染。
前端渲染的优势:
局部更新页面,无需每次都进行完整页面请求
懒加载。页面初始时只加载可视区域内的数据,随着滚动等操作再加载其他数据
节约服务器成本
关注分离设计。服务器只用于访问数据库提供接口,前端关注展现。
富交互,使用 JS 实现各种酷炫效果
·跨域
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。
链接: link.
·栅格式布局
栅格化定义:以规则的网格阵列来指导和规范网页中的版面布局以及信息分布。网页栅格系统是从平面栅格系统中发展而来。对于网页设计来说,栅格系统的使用,不仅可以让网页的信息呈现更加美观易读,更具可用性。而且,对于前端开发来说,网页将更加的灵活与规范。
·阻止冒泡的方法
$('.butt').on('click',function(){
console.log('buttonbuttonbutton');
return false; //或者改成 event.stopPropagation();
});
常用的是在要实现的事件的Js代码末尾加个return false; 或者event.stopPropagation();
1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)
2.return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)
3.event.preventDefault();
它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转)
·jq的认知
封装了我们开发过程中常用的一些功能,方便我们调用,提高开发效率和便捷的操控DOM。
·移动端的适配(不同尺寸屏幕)
所谓移动端适配,就是WebApp在不同尺寸的屏幕上等比显示
适配总结:链接: link.
rem单位
var designWidth = 375; // 设计稿宽度
var remPx = 100; // 在屏幕宽度375px,的时候,设置根元素字体大小 100px
var scale = window.innerWidth / designWidth; //计算当前屏幕的宽度与设计稿比例
// 根据屏幕宽度 动态计算根元素的 字体大小
document.documentElement.style.fontSize = scale*remPx + 'px';
五种适配方式:链接: link.
·适配不同浏览器
市场上浏览器种类很多,不同浏览器的内核也不尽相同,所以各个浏览器对网页的解析存在一定的差异。
浏览器内核主要分为两种,一是渲染引擎,另一个是js 引擎,内核更加倾向于说渲染引擎。
常见的浏览器内核:
常见的浏览器内核可以分四种:Trident、Gecko、Blink、Webkit
链接: link.
大屏适配
链接: link.
·设计稿
链接: link.
·数组重复去重
方法一:循环遍历截取
方法二:借助indexOf()方法
方法三:借助新数组和indexOf()方法
方法四:借助空对象
方法五:filter方法
方法六:使用include方法
方法七:es6 新增数据结构 new Set()方法
链接: link.
·模块化、组件化
在前端开发中为了提高网页的开发效率,提高代码的复用率,同时降低块与块之间的耦合性。
组件化更多关注的是UI部分,比如头部,内容区,弹出框甚至确认按钮都可以成为一个组件,每个组件有独立的HTML、css、js代码。
而模块化侧重的功能的封装,主要是针对Javascript代码,隔离、组织复制的javascript代码,将它封装成一个个具有特定功能的的模块,有了模块,我们就可以更方便地使用别人的代码,想要什么模块就加载什么模块,但是模块开发遵循一定的规范,及ADM规范和CMD规范。
注释:
AMD规范:”异步模块定义“的意思,采用的是异步加载模块,模块的加载不影响后面语句的运行,所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行
CMD规范:CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,同时,CMD是在SeaaJS推广的过程中形成的,CMD和AMD要解决的都是同个问题,在使用上也都很像,只不过两者在模块定义方式和模块加载时机上有所不同
·dom的事件流
事件捕获阶段(从父到子)
处于目标阶段
事件冒泡阶段(从子到父)
·网页卡顿
1、渲染不及时,页面掉帧
长时间占用js线程
页面回流和重绘较多
资源加载阻塞
2、内存过大导致的页面卡顿
内存泄漏导致内存过大
意外的全局变量引起的内存泄漏
闭包引起的内存泄漏
被遗忘的定时器
循环引用
DOM删除时没有解绑事件
没有清理的DOM元素引用
dom节点或事件占用内存过大
链接: link.
·懒加载
懒加载是一种在页面加载时延迟加载一些非关键资源的技术,换句话说就是按需加载。
1、浪费流量。在不计流量收费的网络,这可能不重要;在按流量收费的网络中,毫无疑问,一次性加载大量图片就是在浪费用户的钱。
2、消耗额外的电量和其他的系统资源,并且延长了浏览器解析的时间。因为媒体资源在被下载完成后,浏览器必须对它进行解码,然后渲染在视窗上,这些操作都需要一定的时间。
懒加载图片和视频,可以减少页面加载的时间、页面的大小和降低系统资源的占用,这些对于性能都有显著地提升。总体来讲,就是改善用户体验,增强页面性能。
链接: link.
·出现卡顿怎么排查
页面卡顿,可能涉及到很多页面性能问题,有可能是来自前端,有可能是来自后端,也有可能是来自用户网络问题等。
- 有可能是前端加载的某些js文件加载失败了或者是报错了
- 有可能是该页面请求的接口太多了,导致数据返回慢,可适当做缓存
- 有可能是浏览器渲染的东西太多导致卡顿。
但页面卡顿更大的可能是来自内存泄漏。
·pormise
promise是一个异步解决方案,主要是解决了回调地域的问题
链接: link.
·前端性能优化
包括减少请求数量、减小资源大小、优化网络连接、优化资源加载、减少重绘回流、使用性能更好的API和构建优化
链接: link.
·异步
其实同步和异步,无论如何,做事情的时候都是只有一条流水线(单线程),同步和异步的差别就在于这条流水线上各个流程的执行顺序不同
最基础的异步是setTimeout和setInterval函数,很常见,但是很少人有人知道其实这就是异步,因为它们可以控制js的执行顺序。我们也可以简单地理解为:可以改变程序正常执行顺序的操作就可以看成是异步操作。
尽管setTimeout的time延迟时间为0,其中的function也会被放入一个队列中,等待下一个机会执行,当前的代码(指不需要加入队列中的程序)必须在该队列的程序完成之前完成,因此结果可能不与预期结果相同。
- 于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task
queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。
异步运行机制如下:
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
“任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等),比如$(selectot).click(function),这些都是相对耗时的操作。只要指定过这些事件的回调函数,这些事件发生时就会进入"任务队列”,等待主线程读取。
宏任务和微任务
console.log('start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
new Promise((resolve) => {
console.log('promise')
resolve()
})
.then(() => {
console.log('then1')
})
.then(() => {
console.log('then2')
})
console.log('end')
start
promise
end
then1
then2
setTimeout
执行栈选择最先进入队列的宏任务(一般都是script),执行其同步代码直至结束;
检查是否存在微任务,有则会执行至微任务队列为空;
如果宿主为浏览器,可能会渲染页面;
开始下一轮tick,执行宏任务中的异步代码(setTimeout等回调)。
promise
异步回调的一个很大的问题在于callback hell也就是“回调地狱”。多层嵌套回调函数,严重影响代码规范。Promise实际上是把回调函数从doSomething函数中提取到了后面的then()方法里,从而防止多重嵌套。一个Promise对象表示目前还不可用但是未来某个节点可以被解析的值,这个值要么被解析成功,要么失败抛出异常。它允许我们以同步的方式编写异步代码。
async/await
async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
await 等到了它要等的东西,一个 Promise 对象,或者其它值,await 是个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西。
- 如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。
- 如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到
resolve 的值,作为 await 表达式的运算结果。
await 必须用在 async 函数中的原因:
async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。
apply()和call()
call 的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面obj.myFun.call(db,‘江西’, …, ‘string’)。
apply的所有参数都必须放在一个数组里面传进去。
- apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
语法:apply([thisObj [,argArray] ]);,调用一个对象的一个方法,2另一个对象替换当前对象。
- call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
语法:call([thisObject[,arg1 [,arg2 [,…,argn]]]]);,应用某一对象的一个方法,用另一个对象替换当前对象。
链接: link.
Local storage、session storage、cookie 的区别
cookie是服务器发送到客户端进行存储的文本,可以设置失效时间,用于发起请求自动携带到请求头,服务端和客户端进行信息传递的
链接: link.
函数、变量提升
每次当控制器转到可执行代码的时候,就会进入一个可执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。
链接: link.
三次握手,四次挥手
TCP协议在传输数据的时候,客户端(Client)跟服务端(Server)会建立连接,然后把需要传输的文件进行分段,以及提供可靠传输和流量控制,在数据传输完成后,当前的会话也要断开连接,避免资源浪费。其实TCP的三次握手就是建立连接的过程,而四次挥手就是断开连接的过程。
链接: link.
登录流程
登录:当用户填写账号和密码点击登录按钮向服务端检验是否正确,检验通过后,服务端返回一个token,前端存储token到cookie中,然后根据这个token去获取用户的详细信息,获取到该用户的权限
权限:通过获取用户信息对应的权限,筛选生成该权限的路由列表,使用addRouters动态添加进去。
目前主要的设计思路都是基于Vue-Router配合后端返回角色权限定义进行设计。后端返回角色对应路由权限数据,返回形如 { role: ‘admin’, permissions: [‘Order’, …] },
其中permissions对应前端路由页面name,通过这样的形式后端动态返回该角色所具备的权限列表,前端配合router.addRoutes动态注册路由,达到路由级的权限控制。
在后台管理系统中对角色进行权限的分配(包括页面权限和接口权限),页面权限可以根据vue-router的api动态的生成路由表,而接口权限就需要后端的同学去进行校验。
在Vue中权限控制的主体思路,前端会有一份路由表,它表示了每一个路由可访问的权限。当用户登录之后,通过 token 获取用户的 role ,动态根据用户的 role 算出其对应有权限的路由,再通过router.addRoutes动态挂载路由。但这些控制都只是页面级的。
- 创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。
- 当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。
- 调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。
- 使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。
//获取auth身份
const routes = [].filter(item => item.meta.auth == getauth)
链接: link.
链接: link.
UDP、TCP
计算机与网络设备要互相通信,比如,如何探测到通信目标、由哪一边先发起通信、使用哪种语言进行通信、怎样结束通信等规则都需要事先确定。不同的硬件、操作系统之间的通信,所有的这一切都需要一种规则。而我们就把这种规则称为协议(protocol)。
UDP
- 在网络中与TCP协议一样用于处理数据包,是一种无连接的协议,面向无连接,但是不需要和TCP发送数据前三次握手建立连接,只管传递数据,不在乎是否能接收
- 有单播,多播,广播的功能
- UDP是面向报文的,发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文
- 不可靠性,无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。并且收到什么数据就传递什么数据,并且也不会备份数据, UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。
TCP
- TCP连接需要三次握手确定连接成功,第一次握手,客户端向服务端发送连接请求报文段。该报文段中包含自身的数据通讯初始序号。请求发送后,客户端便进入 SYN-SENT 状态。第二次握手,服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号,发送完成后便进入 SYN-RECEIVED 状态。第三次握手,当客户端收到连接同意的应答后,还要向服务端发送一个确认报文。客户端发完这个报文段后便进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立成功。
- 面向连接,两端必须建立连接,三次握手
- 仅支持单播传输
- 面向字节流,TCP不像UDP一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。
- 可靠传输,判断丢包,误码靠的是给每个包一个序号,接收端按序接收,成功就发回2一个相应的确认,如果发送端未收到确认,则将重新传输。
- 提供拥塞控制,当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞
所以想要数据准确的选择tcp,数据及时的选择udp
WebSocket
主要作用就是建立服务器和客户端的长连接能更好的节省服务器资源和带宽,服务器向浏览器推流实现实时通信。
实现浏览器与服务器的双向数据传输
构造函数,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的 一种建立在 TCP 协议之上,服务器端的实现比较容易可以发送文本,也可以发送二进制数据没有同源限制
基本类型复制
function clone(value) {
let pd = Object.prototype.toString.call(value)
if(pd == '[object Array]'){
let res = []
for(let n in value) {
res[n] = clone(value[n])
}
return res
}else if(pd == '[object Object]') {
let res = {}
for(let n in value) {
res[n] = clone(value[n])
}
return res
}else {
return value
}
}
去空格
function trim(str) {
return str.replace(/^\s+|\s+$/g, "");
}
冒泡排序
var examplearr=[8,94,15,88,55,76,21,39];
function sortarr(arr){
for(i=0;i<arr.length-1;i++){
for(j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
var temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
return arr;
}
sortarr(examplearr);
console.log(examplearr);
为false数据
null、false、0、undefined、Null、" "
栈和堆
JavaScript中的变量分为基本类型和引用类型
基本类型是保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问
引用类型是保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用
链接: link.
axios
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API,
// 超时
timeout: 10000
})
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
链接: link.