补:get请求传参长度的误区
-
实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是来源与浏览器或web服务器,浏览器或web服务器限制了url的长度。
-
不同的浏览器和WEB服务器,限制的最大长度不一样要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte
补:get和post请求在缓存方面的区别
- get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。
- post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。
1.三次握手and四次挥手
-
三次握手
详细描述:
客户端发送连接请求报文,服务器接受连接后回复ACK报文,并为这次连接分配资源。客户端接收到ACK报文后也向服务器发生ACK报文,并分配资源,这样TCP连接就建立了。
简单的理解:- 客户端看到服务器,打声招呼(
发送syn
); - 服务器收到客户端的招呼,也向客户端打招呼,表示他看到了(
发送syn+ack
) - 客户端看到服务器的回应,相当建立沟通(
发送ack
),表示很开心
详细过程:
- 1)第一次握手:A的TCP客户进程也是首先创建传输控制块TCB,然后向B发出连接请求报文段(首部的同步位SYN=1,初始序号seq=x)
- 2)第二次握手:B收到连接请求报文段后,如同意建立连接,则向A发送确认,在确认报文段中(SYN=1,ACK=1)
- 3)第三次握手:TCP客户进程收到B的确认后,要向B给出确认报文段(ACK=1)
- 客户端看到服务器,打声招呼(
-
四次挥手
TCP断开链接的过程和建立链接的过程比较类似,只不过中间的两部并不总是会合成一步走,所以它分成了4个动作。
简单理解:- 客户端挥手(fin)
- 服务器伤感地微笑(ack)
- 服务器挥手(fin)
- 客户端伤感地微笑(ack)。
详细描述: - 1)客户端发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,客户端进入FIN-WAIT-1(终止等待1)状态
- 2)服务器收到连接释放报文,发出确认报文,ACK=1,服务端就进入了CLOSE-WAIT(关闭等待)状态
- 3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态。
服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1。服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。 - 4) 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1。此时,客户端就进入了TIME-WAIT(时间等待)状态。
注意此时TCP连接还没有释放,必须经过2个MSL(最长报文段寿命)的时间后(即两分钟),当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
- 总的说就是:
客户端要断开,告诉服务器,服务器同意断开连接。
服务器发送完最后数据,服务器要断开,告诉客户端,客户端同意断开连接。
客户端同意断开连接,服务器立马close。但是客户端还要等待两分钟。
- 为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:中间的两个动作没有合并,是因为tcp存在「半关闭」状态,也就是单向关闭。
因为当Server端收到Client端的syn连接请求报文后,可以直接发送syn+ack报文。其中ack报文是用来应答的,syn报文是用来同步的。但是关闭连接时,当Server端收到fin报文时,很可能并不会立即关闭,所以只能先回复一个ack报文,告诉Client端,"你发的fin报文我收到了"。只有等到我Server端所有的数据报文都发送完了,我才能发送fin报文,因此不能一起发送。故需要四步握手。
- 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
2.url到页面渲染完成的经过
大致分为三步:
-
1. 域名解析
- 浏览器会将输入的域名解析成相应的ip地址
- 查看浏览器内部缓存
- 查看本机的host文件,会查看本机的host文件下,是否存了对应的ip地址
- 本地路由器的DNS解析
- 查看网络服务DNS
- 查询到ip地址后,开始建立TCP三次握手,与服务器建立连接
- 通过协议(http)向目标主机发送请求
-
2. 服务器接收请求并返回数据
- 服务器接收到了浏览器发送的请求后,根据某个协议,通过web-server把浏览器发送的数据进行打包(包含请求头,ip地址,请求路径和查询参数等)
- web-server把数据打包后,发送给网站代码(比如django、flask、node.js等后端服务)
- 后端服务软件会根据路径和查询参数进行相应处理,返回给浏览器对应的数据包(包括http协议组成的代码。里面包含页面的布局、文字。数据也可能是图片、脚本程序,反应头,反应数据,请求头等)
-
3. 浏览器接收数据并渲染页面
- 浏览器接收到返回的数据包,根据浏览器的渲染机制对相应的数据进行渲染。
- 渲染后的数据,进行相应的页面呈现和脚步的交互。
3.js引擎的执行机制
(1) JS是单线程语言
(2) JS的 Event Loop是JS的执行机制。
-
js为什么是单线程的呢?
因为,如果是多线程,若几个线程同时操作dom的话,浏览器该怎么执行呢。 -
js为什么需要异步呢?
js中不存在异步,是从上而下顺序执行的,但是这样很容易阻塞,若某一句代码解析执行时间很长,那用户就需要等待很长时间,所以需要异步执行。 -
js怎么实现异步呢?
就是通过本节的核心事件循环(Event Loop)了,那事件循环具体是什么呢?
比如:
cosole.log(1);
setTimeOut(function(){
cosole.log(2);
},0);
cosole.log(3);
执行的输出顺序是: 1 3 2
js是顺序从上到下执行,但是setTimeOut是最后才执行的,就证明了异步的存在。js也就将任务分为:同步任务和异步任务。
-
那事件循环具体怎么循环?
- 1.js判断是同步事件还是异步事件,同步就进入执行栈,异步事件被挂起
- 异步事件返回结果后,就进入消息队列
- 同步任务进入执行栈后一直执行,直到执行栈为空时,才会去消息队列中查看是否有可执行的异步任务,如果有就推入执行栈中
循环执行上述三步,直到执行栈为空,就是事件循环了
所以上面例子的执行顺序分析是怎样的呢?
console.log(1) 是同步任务,放入主线程(执行栈)里
setTimeout() 是 异步任务,被挂起, 0秒之后被推入消息队列里
console.log(3 是同步任务,放到主线程(执行栈)里
当 1、 3输出后,主线程去消息队列(事件队列)里查看是否有可执行的函数,执行setTimeout里的函数,输出2
以上就是event loop 的简单分析了。但是只是很浅的一部分,因为还有下面这样情况:
setTimeout(function(){
console.log('定时器')
});
new Promise(function(resolve){
console.log('开始for循环');
for(var i = 0; i < 10000; i++){
i == 99 && resolve();
}
}).then(function(){
console.log('执行then')
});
console.log('执行结束');
对于这样多个异步的事件,按照之前的分析应该输出:开始for循环 --> 执行结束 --> 定时器 --> 执行then
但是实际的输出却是: 开始for循环 --> 执行结束 --> 执行then --> 定时器
会发现 是 先执行promise 再执行的setTimeOut ,那难道是异步任务的执行顺序,不是前后顺序,而是另有规定? 事实上,按照异步和同步的划分方式,并不准确。
而准确的划分方式是:
- macro-task(宏任务):包括整体代码script,setTimeout,setInterval
- micro-task(微任务):Promise,process.nextTick
按照这种分类方式:JS的执行机制是
-
执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的【事件队列】里
-
当前宏任务执行完成后,会查看微任务的【事件队列】,并将里面全部的微任务依次执行完
重复以上2步骤,再结合前面的事件循环,就是更为准确的JS执行机制了。
所以上面例子的执行顺序分析是怎样的呢?
先执行script宏任务
遇到 setTimeOut 是宏任务,将其放入宏任务队列
遇到 new Promise直接执行,打印 "开始for循环"
遇到 then 是微任务,将其放入微任务队列
打印 "执行结束"
本轮宏任务(script)执行完毕,检查微任务队列,遇到then,执行输出 " 执行then",就只有这一个微任务,所以执行结束
本轮 event loop 执行结束
进入下一轮
执行宏任务 setTimeOut,打印 "定时器"
再查看微任务队列,没有微任务
执行完毕
4.hash与history的区别
-
hash模式
- hash就是指url尾巴后的#号以及后面的字符,hash值变化不会导致浏览器向服务器发出请求,而且hash改变会触发hashchange事件,浏览器的进后退也能对其进行控制,所以人们在html5的history出现前,基本都是使用hash来实现前端路由的。
- hash出现url中,但不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。
- hash 本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。其次,hash的传参是基于url的,如果要传递复杂的数据,会有体积的限制
-
history模式
- history模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。
history——— 利用了HTML5 History Interface 中新增的 pushState()和replaceState()方法。
(需要特定浏览器的支持)history不能运用与IE8一下
- history模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。
-
pushState()和 replaceState()的区别:
- pushState 是创建新的历史纪录
- replaceState是修改当前历史纪录
window.history.pushState(state,title,url)
state:需要保存的数据,这个数据在触发popstate事件时,可以在event.state里获取
title:标题,基本没用,一般传null
url:设定新的历史纪录的url。新的url与当前url的origin必须是一样的,否则会抛出错误。url可以时绝对路径,也可以是相对路径。
如 当前url是 https://www.baidu.com/a/,执行history.pushState(null, null, './qq/'),则变成 https://www.baidu.com/a/qq/,
执行history.pushState(null, null, '/qq/'),则变成 https://www.baidu.com/qq/
window.history.replaceState(state,title,url)
与pushState 基本相同,但她是修改当前历史纪录,而 pushState 是创建新的历史纪录
window.addEventListener("pospstate",function(){
监听浏览器前进后退事件,pushState与replaceState方法不会触发
})
window.history.back() 后退
window.history.forward() 前进
window.history.go(1) 前进一部,-2回退两不,window.history.lengthk可以查看当前历史堆栈中页面的数量
这两个方法应用于浏览器的历史纪录站,在当前已有的back、forward、go 的基础之上,他们提供了对历史纪录进行修改的功能,只是当他们执行修改使,虽然改变了当前的url,但你的浏览器不会立即像后端发送请求。
- 404错误
1、hash模式下,仅hash符号之前的内容会被包含在请求中,如 http://www.abc.com 因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回404错误;
2、history模式下,前端的url必须和实际后端发起请求的url一致,如http://www.abc.com/book/id 。如果后端缺少对/book/id 的路由处理,将返回404错误。
5.vue钩子函数
(1)与生命周期有关的生命周期函数: beforeCreate
、created
、beforeMounted
、mounted
、beforeUpdate
、updated
、beforeDestory
、destoryed
。
(2)computed
、watch
、filter
等
(3)自定义指令directive
的钩子函数
-
bind
: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作 -
inserted
:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document) -
update
: 被绑定元素所在的模板更新时调用,而不论绑定值是否 -
componentUpdated
: 被绑定元素所在模板完成一次更新周期时调 -
unbind
: 只调用一次,指令与元素解绑时
常用参考链接:https://www.jianshu.com/p/8314ccd03fa9
6.vue常用指令
-
v-for
v-for="字段名 in(of) 数组json" 循环数组或json -
v-model
数据的双向绑定 -
v-if
显示与隐藏 ,是创建和删除元素 -
v-else-if
必须和v-if连用 -
v-else
必须和v-if连用 不能单独使用 否则报错 模板编译错误-
v-show
显示内容,只是切换display值 -
v-hidden
隐藏内容
-
-
v-bind
动态绑定 -
v-bind:class
3种绑定方法- 1.对象型
{red:isred}
- 2.三元型
isred?"red":"blue"
- 3.数组型
[{red:"isred"},{blue:"isblue"}]
- 1.对象型
-
v-on
监听dom事件,可以缩写为@,例如绑定一个点击函数 ,函数必须写在methods里面 -
v-text
解析文本 -
v-html
解析html标签 -
v-once
进入页面时 ,只渲染一次,不在进行渲染
常用参考链接:https://blog.csdn.net/dz13271116886/article/details/99708315
7.vue常用修饰符
-
事件修饰符(5个)
-
.stop
:阻止事件冒泡 -
.prevent
:阻止默认事件 -
.once
:只执行一次 -
.capture
:捕获事件,与冒泡相反 -
.self
:只触发自身事件
-
-
键盘修饰符(9个)
-
.enter
:回车键 -
.tab
:制表键 -
.delete
:含delete和backspace键 -
.esc
:返回键 -
.space
: 空格键 -
.up
:向上键 -
.down
:向下键 -
.left
:向左键 -
.right
:向右键
-
-
v-modle修饰符(3个)
-
.number
:将输出字符串转为Number类型 -
.lazy
:在改变后才触发(也就是说只有光标离开input输入框的时候值才会改变) -
.trim
:自动过滤用户输入的首尾空格
-
详细参考链接:https://blog.csdn.net/qq_42238554/article/details/86592295
8.vue常用组件
-
vue-cli
: 项目构建工具 -
vue-router
:路由 -
vuex
:状态管理 -
axios
:http请求 - 组件库的组件 eg:Element-ui 、iview
详细参考链接:sohu.com/a/328202078_120047065
9.vue 过滤器
在vue中提供了Vue.filter('filterName',fn)
来定义一个过滤器。
过滤器可以在HTML代码中使用,对动态拿到的数据进行过滤。
filter不会修改原始数据,它的作用是过滤数据。
通过|
管道符来过滤前面数据
- 过滤器参数:
- 第一个参数 fliterName:是过滤器的名字
- 第二个参数 fn :是过滤器功能函数(两个参数)
- 过滤功能函数参数:
- 第一个参数是传入的要过滤数据,即原数据。
- 第二个参数开始就是html调用过滤器的时候传入的参数。
用法参考链接:https://blog.csdn.net/badmoonc/article/details/81485803
10.MVVM的理解
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。
响应式原理
观察者-订阅者(数据劫持):
- vueObserver 数据监听器,把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty()方法把这些属性全部转成setter、getter方法。当data中的某个属性被访问时,则会调用getter方法,当data中的属性被改变时,则会调用setter方法。
- Compile指令解析器,它的作用对每个元素节点的指令进行解析,替换模板数据,并绑定对应的更新函数,初始化相应的订阅。
- Watcher 订阅者,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。
- Dep 消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify 函数,再调用订阅者的 update 方法
实现方法:
- 1.实现compile,进行模板的编译,包括编译元素(指令)、编译文本等,达到初始化视图的目的,并且还需要绑定好更新函数;
- 2.实现Observe,监听所有的数据,并对变化数据发布通知;
- 3.实现watcher,作为一个中枢,接收到observe发来的通知,并执行compile中相应的更新方法。
-
4.结合上述方法,向外暴露mvvm方法。
执行过程
过程描述:
(1) 当创建一个vue对象时,先进入初始化阶段:(两部分工作)
一方面:vue 会遍历data的所有属性,通过object.defineproprety()方法,将所有属性变成setter和getter。 另一方面:vue的指令编译器Complie会解析每个元素节点,初始化视图,然后由watcher(订阅者)更新视图,此时watcher会将自身添加到消息订阅器(Dep)中,初始化完毕。
(2) 当数据变化时:会触发 observer数据监听器中的setter方法,setter 会调用Dep中的方法,此时Dep会去遍历所有的订阅者,然后去调用订阅者的update方法,通知订阅者进行视图更新。
参考:https://segmentfault.com/a/1190000018399478
11.vue生命周期
Vue实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载等一系列过程
-
beforeCreate
:创建之前,在实例初始化之后,数据观测和事件配置之前被调用。 -
created
: 创建完成,实例已完成以下配置:数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,el没有。此时dom还没渲染,可以在此处进行ajax请求。 -
beforeMount
: 挂载之前,相关的render函数首次被调用(虚拟DOM),实例已完成以下的配置: 编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂在html到页面上。 -
mounted
:挂载完成,此时dom已渲染完成,可以访问dom元素,只在挂载到vue 对象上执行一次,而后每次更新执行的都是update -
beforeUpdate
:在数据更新之前被调用 -
updated
:数据更新之后,该钩子在服务器端渲染期间不被调用 -
beforeDestroy
:销毁之前,此时vue实例依然可以使用 -
destroyed
:销毁,所有的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用
详细参考连接:https://www.jianshu.com/p/672e967e201c
12.vue动态路由
在vue项目中,使用vue-router如果进行不传递参数的路由模式,则称为静态路由;
如果能够传递参数,对应的路由数量是不确定的,此时的路由称为动态路由。
比如在写商品详情页面的时候,页面结构都一样,只是商品id的不同,所以这个时候就可以用动态路由动态。
冒号后面就是动态的参数
路由配置:
const router = new VueRouter({
routers:[
{
path:'/home:id'
name:'home'
component:home
}
]
});
使用:
<template>
<div>
<router-link to="/home/10">衣服</router-link>
<router-link to="/home/11">麻辣火锅</router-link>
<router-link to="/home/12">肉夹馍</router-link>
</div>
</template>
实现参数传递的方法:
- 使用query传参,name属性为要跳转的组件所对应的name,query为要携带的参数
<router-link :to="{name:'main','query':{data:'allData'}}"></router-link>
- 使用params传参,name属性为要跳转的组件所对应的name,params为要携带的参数
<router-link :to="{name:'main','params':{data:'allData'}}"></router-link>
- 使用params传参时,url中不会出现参数,页面刷新后参数会消失
- 使用query传参时,url中会出现参数,页面刷新后参数不会消失
3.设置页面默认的路由参数(query/params):
this.$router.push( {name: 'main', 'query': {data: 'allData'} } )
this.$router.push( {path: '/main', 'query': {data: 'allData'} } )
- 在组件中接受参数 :
this.$route.query.data || this.$route.params.data
13.post、get、put、delete
post、get、put、delete就像对应着数据库的CRUD(增、删、改、查)
post /url 创建
delete /url/xxx 删除
put /url/xxx 更新或创建
get /url/xxx 查询
(1) get请求,请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的,具有幂等性。
(2) put 请求,求是向服务器端发送数据的(与get不同)从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次put操作,其结果并没有不同,具有幂等性。
(3) post 请求,与put请求类似。都是向服务器端发送数据求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。几乎目前所有的提交操作都是用POST请求的。不具有幂等性。
(4) delete 请求,用来删除某一资源,该请求就像数据库的delete操作。
put 与post 的共同点及区别?
- put和post 都是向服务器发送数据
- post 主要是在一个集合资源之上(url),put 主要作用在一个具体的资源之上(url/xxx)
- put 通常指定了资源的存放位置,而post没有。post的数据存放位置由服务器自己决定,如果url可以在客户端确定,那么可使用put,否则用post
- put 有等幂性,而post没有。
幂等性:幂等意味着对同一个URL的多次请求会返回一样的结果
14.跨域方法
- jsonp
- CORS
- webSocket
- postMessage
详情链接:http://www.imooc.com/article/40074
15.vue插件(图表,excel)
16.callback、promise、async-await
17.map、reduce、filter、forEach
- map、filter、reduce会返回新数组,返回值是新数组或结果
- forEach会改变原来数组,forEach没有返回值
- map:用来迭代对数组进行统一的操作(运算),返回一个新数组
- reduce: 用来迭代一个数组,并且把它累积到一个值中
- filter:用来迭代一个数组,并且按给出的条件过滤出符合的元素
18.for、forEach、 for-in 、 for-of
-
for循环
遍历数组 -
forEach循环
遍历数组,对象(不包括原型上的属性)
循环不能中途退出,不能使用break,return -
for-in
这个循环是特别针对遍历对象属性的。
会遍历对象的所有属性,包括原型上的属性和自定义属性
对象的属性是没有顺序的,所以for-in遍历属性输出也是没有顺序的
若对象是null或undefined有可能会报错 -
for-of
这个循环是最棒的,不仅支持数组,还支持遍历类数组对象和其他可迭代对象。
可以使用 break、continue、return
for-of循环也支持字符串遍历,将字符串视为一系列的Unicode字符来进行遍历
for-of也支持Map和Set遍历。
for-of不遍历普通对象。
小总结:
- for-in循环的每次迭代操作会同时搜索实例或者原型属性,for-in循环的每次迭代会产生很多开销。除非明确要迭代一个属性数量未知的对象,否则应该避免使用。 for-in 并不适合用来遍历数组中的元素,其更适合遍历对象中的属性。
- forEach循环不会遍历原型链上的属性,不能break和return。
- for-of 循环这是最直接、最简洁的遍历数组的方法。这个方法避开了for-in循环的所有缺陷
- forEach 的速度不如 for
-
for in循环出的是key,for of循环出的是value
for-in 、for-of遍历普通对象
let arr = {
name:'aaa',
age:23,
sex:'女'
}
普通对象要加可枚举的属性Object.keys(),不然报错
for(let i of Object.keys(arr)){
console.log(i);
} //name age sex
for(let i in arr){
console.log(i);
} //name age sex
for-of 遍历 Map ,初始是一个二维数组,对应的键值匹配
let test = new Map([['name','aaa'],['age',12],['sex','女']]);
for (var [key, value] of test) {
console.log(key +" is "+ value);
}
//name is aaa
//age is 12
//sex is 女
for-of 遍历 Set ,遍历同时会进行数组的去重
var test = new Set([1,1,2,3,4,5]);
for (var i of test) {
console.log(i);
}
//1,2,3,4,5
网友评论