前端面试技术整理
BOM&&DOM#
1.BOM事件?#
事件就是用户或浏览器自身执行的某种动作.事件可能是用户在某些内容上的点击、鼠标经
过某个特定元素或按下键盘上的某些按键。事件还可能是 Web 浏览器中发生的事情,比如说某个 Web
页面加载完成,或者是用户滚动窗口或改变窗口大小。
通过使用 JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应。
JavaScript可以处理的事件类型为:鼠标事件、键盘事件、HTML事件
2.常见BOM事件?#
load:当页面或图像加载完后立即触发
blur:元素失去焦点
focus:元素获得焦点
click:鼠标点击某个对象
change:用户改变域的内容
mouseover:鼠标移动到某个元素上
mouseout:鼠标从某个元素上离开
keyup:某个键盘的键被松开
keydown:某个键盘的键被按下
3.BOM事件处理程序?#
响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以“on”开头,因此
click事件的事件处理程序就是onclick,为事件指定处理程序的方式有好几种
4.BOM对象方法?#
这里主要说一下系统对话框:
浏览器通过(实际是window对象的方法)alert()、confirm()、prompt()方法可以调用系统对话框向用
户显示消息
消息框:alert, 常用。
alert() 方法用于显示带有一条指定消息和一个 OK 按钮的警告框。
输入框:prompt,返回提示框中的值。
prompt() 方法用于显示可提示用户进行输入的对话框。
参数(可选):
第一个参数:要在对话框中显示的纯文本。
第二个参数:默认的输入文本。
确认框:confirm,返回 true/false.
confirm() 方法用于显示一个带有指定消息和 OK 及取消按钮的对话框。
5.BOM对象#
1.history
history 对象是历史对象。包含用户(在浏览器窗口中)访问过的 URL。history 对象是 window 对象的
一部分,可通过 window.history 属性对其进行访问。
history对象的属性:length,返回浏览器历史列表中的 URL 数量。
history对象的方法:
back():加载 history 列表中的前一个 URL。
forward():加载历史列表中的下一个 URL。当页面第一次访问时,还没有下一个url。
go(number|URL): URL 参数使用的是要访问的 URL。而 number 参数使用的是要访问的 URL 在
History 的 URL 列表中的相对位置。go(-1),到上一个页面
2.location
location 对象是window对象之一,提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功
能。也可通过 window.location 属性来访问。
location 对象的属性href:设置或返回完整的 URL
location 对象的方法
reload():重新加载当前文档。
replace():用新的文档替换当前文档。
3.document
6.DOM?#
DOM:Document Object Model 文档对象模型
要实现页面的动态交互效果,bom 操作远远不够,需要操作 html 才是核心。如何操作 htm,就是DOM。
简单的说,dom 提供了用程序动态控制 html 接口。DOM即文档对象模型描绘了一个层次化的节点树,
运行开发人员添加、移除和修改页面的某一部分。dom 处于javascript 的核心地位上。
每个载入浏览器的 HTML 文档都会成为 Document 对象。Document 对象使我们可以从脚本中对
HTML 页面中的所有元素进行访问。Document 对象是 Window 对象的一部分,可通过window.document 属性对其进行访问。
7.DOM获取节点#
获取节点的四种方法:
getElementById()--通过id属性值获取元素对象
getElementByName()--通过name属性值获取元素对象数组
getElementByClass()--通过class属性值获取元素对象数组
getElementByTagName()--通过元素名/标签名获取元素对象数
后三个获取的是数组,所以需要通过数组下标取值
注意:操作dom节点是在等节点初始化完毕后,才会执行
处理方式:
把script标签移到html末尾即可
使用onload事件来处理JS,等待html加载完毕再加载onload事件里的JS
9.DOM0级和DOM2级有什么区别#
DOM0级中为某个dom元素绑定多个事件时,只有最后一个事件有效。onclick
DOM2级中可以为单个元素绑定多个事件,每个事件都可以被触发。addEventListener
10.textContent、innerText、innnerHTML、value的区别#
textContent用来获取和设置文本内容,与innerText的差别是:textContent获取到的内容包括了元素中
的style标签和script标签的内容。
innerText只能获取和设置文本内容,不能获取和设置html代码
innerHTML可以获取和设置html代码
value获取的是表单元素的值
11.关于dom的api有什么#
节点创建型api:
document.createElement()
document,createTextNode()
parent.cloneNode(true)
document.createDocumentFragment() 创建文档片段,解决大量添加节点造成的回流问题
页面修改型API:
parent.appendChild(child)
parent.insertBefore(newNode,referenceNode) 将新元素添加到父元素中指定的子元素前面
parent.removeChild(child)
parent.replcaeChild(newChild,oldChild)
节点查询型API:
document.getElementById()
document.getElementsByTagName() 返回的是一个即时的HTMLCollection类型
document.getElementsByName() 根据指定的name属性获取元素,返回的是一个即时的NodeList
document.getElementsByClassName() 返回的是一个即时的HTMLCollection
document.querySelector() 获取匹配到的第一个元素,采用的是深度优先搜索。
docuemnt.querySelectorAll()
返回的是一个非即时的NodeList,也就是说结果不会随着文档树的变化而变化
节点关系型api:
父关系型:
node.parentNode()
兄弟关系型
node.previouSibling() 返回节点的前一个节点(包括元素节点,文本节点,注释节点)
node.previousElementSibling() 返回前一个元素节点
node.nextSibling() 返回下一个节点
node.nextElementSibling() 返回下一个元素节点
子关系型
parent.childNodes() 返回一个即时的NodeList,包括了文本节点和注释节点
parent.children() 一个即时的HTMLCollection,子节点都是Element
parent.firsrtNode()
parent.lastNode()
hasChildNodes()
元素属性型api:
element.setAttribute(“name”,“value”) 为元素添加属性
element.getAtrribute(“name”) 获取元素的属性
元素样式型api:
window.getComputedStyle(element) 返回一个CSSStyleDeclaration,可以从中访问元素的任意样式属
性。
element.getBoundingClientRect() 返回一个DOMRect对象,里面⭐️包括了元素相对于可视区的位置
top,left,以及元素的大小,单位为纯数字。可用于判断某元素是否出现在了可视区域。
12.什么叫Dom事件流?#
事件发生时会在元素节点之间按照特定的顺序传播,整个过程分为捕获阶段,目标阶段和冒泡阶段,这
个传播过程叫做Dom事件流。
事件冒泡:从事件源逐级向上传播到DOM最顶层节点的过程。
事件捕获:从DOM最顶层节点逐级向下传播到事件源的过程。
addEventListener用于指定事件处理程序,共接收三个参数。分别是触发事件,事件处理程序函数以及
一个布尔值。第三个参数默认为false,表示在该事件的处理函数会在冒泡阶段被调用。若改为true,则
表示事件处理函数会在捕获阶段被调用。
IE只支持事件冒泡。
13.如何让事件先冒泡后捕获#
原本的事件流中,是先捕获再冒泡。
对于目标元素来说,如果DOM节点通过addEventListener同时绑定了两个事件监听函数,一个用于捕
获,一个用于冒泡,那么两个事件的执行顺序是按照代码添加的顺序执行的。所以,先绑定冒泡的函
数,再绑定捕获的函数,即可实现。
对于非目标元素来说,可以给捕获事件的处理程序添加一个定时器,将处理程序推入下一个宏任务执
行。
14.说一下事件代理#
事件委托是指 不在子节点单独设置事件监听器,而将事件监听器设置在父节点上,再利用冒泡原理使每
一个子节点都能触发该事件。
事件委托的优点:只操作一次Dom,提高了程序的性能。
常用于
ul和li标签的事件监听,一般采用事件委托机制将事件监听器绑定在ul上。
还适合动态元素的绑定,新添加的子元素不需单独添加事件处理程序。
(1)了解事件代理吗,这样做有什么好处
事件代理/事件委托:利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的事件,
简而言之:事件代理就是说我们将事件添加到本来要添加的事件的父节点,将事件委托给父节点来触发
处理函数,这通常会使用在大量的同级元素需要添加同一类事件的时候,比如一个动态的非常多的列
表,需要为每个列表项都添加点击事件,这时就可以使用事件代理,通过判断e.target.nodeName来判
断发生的具体元素,这样做的好处是减少事件绑定,同事动态的DOM结构任然可以监听,事件代理发生
在冒泡阶段
(2)事件委托以及冒泡原理:
事件委托是利用冒泡阶段的运行机制来实现的,就是把一个元素响应事件的函数委托到另一个元素,一
般是把一组元素的事件委托到他的父元素上。
委托的优点是减少内存消耗,节约效率
动态绑定事件
事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick事件,那么元素本身的
触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到
document/window,冒泡过程结束。
(3)事件代理在捕获阶段的实际应用:
可以在父元素层面阻止事件向子元素传播,也可代替子元素执行某些操作。
html和css部分#
1. 如何理解CSS盒子模型#
标准盒子模型:宽度=内容的宽度(content)+ border + padding
低版本IE盒子模型:宽度=内容宽度(content+border+padding)
2.BFC#
## html和css部分
#### 1. 如何理解CSS盒子模型
标准盒子模型:宽度=内容的宽度(content)+ border + padding
低版本IE盒子模型:宽度=内容宽度(content+border+padding)
#### 2.BFC
•```html
* 什么是 BFC
BFC(Block Formatting Context)格式化上下文,是 Web 页面中盒模型布局的 CSS 渲染模式,
指一个独立的渲染区域或者说是一个隔离的独立容器。
* 形成 BFC 的条件
* 浮动元素,float 除 none 以外的值
* 定位元素,position(absolute,fixed)
* display 为以下其中之一的值 inline-block,table-cell,table-caption
* overflow 除了 visible 以外的值(hidden,auto,scroll)
* BFC 的特性
* 内部的 Box 会在垂直方向上一个接一个的放置。
* 垂直方向上的距离由 margin 决定
* bfc 的区域不会与 float 的元素区域重叠。
* 计算 bfc 的高度时,浮动元素也参与计算
* bfc 就是页面上的一个独立容器,容器里面的子元素不会影响外面元素。
•```
3.标签语义化#
代码结构更加清晰
见名知意,没有基础的人也能知道这部分代码是干嘛的
方便团队开发维护,代码可读性更强
有利于SEO优化,爬虫依赖于标签来确定上下文关系
4.meta标签#
meta标签提供关于html文档的元数据,不会显示在页面,但是对于机器是可读的,告诉浏览器怎么解析页
面,告诉搜索引擎关键字(SEO优化)
meta作用:告诉机器浏览器该如何解析该页面,描述这个页面的主要内容,可以设置服务器发送到浏览器的
http头部内容
charset="utf-8"设置页面使用的字符编码
viewport 设置视口,移动端的适配
5.css与javascript引入设置#
script标签的引入一般放在body最后,这样避免脚本过大,加载时间长,导致页面长时间空白,这是因为渲
染进程与js进程是互斥的,脚本会阻塞页面的渲染,脚本之间的加载是同步进行的,按引入顺序执行,但是以
下两个属性会影响脚本执行与页面渲染的顺序
defer:不会阻塞渲染,这样即使放在header内部,也不会阻塞页面加载,不过js会先于document加载完
成,并且也不会影响脚本之间的执行顺序,按照引入顺序执行
async:与defer一样,都是解决阻塞渲染,但它是在document加载完成后才执行,并且它的执行顺序是按
照谁先加载完成执行谁,所以对于文件顺序有要求,存在前后依赖的不要使用它
6.HTML的块级元素,行内元素,行内块元素有哪些,区别是什么#
块级元素:div,h1-h6,p,ul,ol,dl,li,hr,dt,dd,form,table
块元素独占一行
宽高生效
默认宽和父元素一样,内容撑开高度
margin,padding全部生效
行内元素:em,i,del,small,strong,ins,span,a
宽高不生效
左右margin生效上下不生效
在一行排列
大小靠内容撑开
padding都生效
行内块元素:img,input(表单元素,除去form)
在一行排列
宽高生效
margin,padding生效
7.CSS3有哪些新特性#
border-radius圆角
border-image 边框图片
border-image: url() top right bottom left
border-width: top right bottom left
box-shadow盒子阴影: x,y,size,opcity
text-shadow文字阴影
linear-gradient 线性渐变
background: linear-gradient(to position , color,color,...,color)
radial-gradient 径向渐变
background: radial-gradient(shap size at position , color,color,...,color)
2D/3D转换 transform:rotate(旋转) scale(缩放) translate(位移)
@media媒体查询,根据屏幕宽度,设置,用来解决移动端适配,根据屏幕大小使相应的css生效
flex布局(弹性盒子)
8.实现元素隐藏#
display:none 不占位,源码可见
opacity: 0 占位,源码可见,透明度0
visibility: hidden 占位,源码可见
position: top:-9999px,left:-9999px 利用定位将元素移出视窗
9.如何实现元素水平居中#
行内元素:text-align:center
块元素: margin: 0 auto
position: left: 50%; transform: translate(-50%)
10.如何实现元素垂直居中#
height = line-height
verticle-align: middle
position: top: 50%; transform: translate(0,-50%)
11.Position#
static 默认
relative 相对定位,不脱标,相对于自身位置进行偏离,不影响元素本身特性,z-index提升层级
absolute 绝对定位,脱标,相对于已有定位的父元素进行偏离,都没有就相对于body进行偏离
fixed 固定定位,脱标,相对于视窗进行偏离
#### 12.定位元素水平垂直居中
宽高固定 position: top:0,left:0,right:0,bottom:0,margin:auto
宽高固定 position:top: 50%, left: 50%, margin-left: -width/2px,margin-top: height/2px
dispaly: flex; justify-content: center,align-items: center(极力推荐)
position: left: 50%,top: 50%; transform: translate(-50%,-50%)
13.清除浮动#
•```
不清楚浮动会发生高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父元素会
发生高度塌陷)
* clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式:
{clear:both;height:0;overflow:hidden;}
* 给浮动元素父级设置高度
* 父级同时浮动(需要给父级同级元素添加浮动)
* 父级设置成inline-block,其margin: 0 auto居中方式失效
* 给父级添加overflow:hidden 清除浮动方法
* 万能清除法 after伪类 清浮动(现在主流方法,推荐使用)
.float_div:after{
content:".";
clear:both;
display:block;
height:0;
overflow:hidden;
visibility:hidden;
}
.float_div{
zoom:1
}
•```
14.css选择器有哪些,选择器的优先级#
- id选择器
- 类选择器
- 属性选择器
- 伪类选择器
- 标签选择器
- 伪元素选择器
- 通配符选择器
优先级:内联样式 > ID选择器(100)> 类选择器(10) = 属性选择器 = 伪类选择器 > 元素选择器(1) =
关系选择器 = 伪元素选择器 > 通配符选择器(0)
!important
后代选择器选全部
子代选择器只选亲孩子
15.各种布局优缺点#
1. float 布局
优点: 比较简单,兼容性也比较好。只要清除浮动做的好,是没有什么问题的缺点:浮动元素是脱离文档
流,要做清除浮动,这个处理不好的话,会带来很多问题,比如高度塌陷等。
2. 绝对布局
优点:很快捷,设置很方便,而且也不容易出问题缺点:绝对定位是脱离文档流的,意味着下面的所有子
元素也会脱离文档流,这就导致了这种方法的有效性和可使用性是比较差的。
3. flex 布局
优点:简单快捷缺点:不支持 IE8 及以下
4. table布局
优点:实现简单,代码少缺点:当其中一个单元格高度超出的时候,两侧的单元格也是会跟着一起变高
的,而有时候这种效果不是我们想要的。
5. grid布局
跟 flex 相似。
16.html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分#
HTML 和 HTML5?
**新特性:**
HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。
拖拽释放(Drag and drop) API
语义化更好的内容标签(header,nav,footer,aside,article,section)
音频、视频API(audio,video)
画布(Canvas) API
地理(Geolocation) API
本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
sessionStorage 的数据在浏览器关闭后自动删除
表单控件,calendar、date、time、email、url、search
新的技术webworker, websocket, Geolocation
**移除元素:**
纯表现的元素:basefont,big,center,font, s,strike,tt,u;
对可用性产生负面影响的元素:frame,frameset,noframes;
**h5新标签兼容:**
IE8/IE7/IE6支持通过document.createElement方法产生的标签,
可以利用这一特性让这些浏览器支持HTML5新标签,
当然最好的方式是直接使用成熟的框架、使用最多的是html5shim框架
•```html
<!--[if lt IE 9]>
<script> src="http://html5shim.googlecode.com/svn/trunk/html5.js"</script>
<![endif]-->
•```
**如何区分:**
DOCTYPE声明\新增的结构元素\功能元素
17. CSS3新增伪类举例:#
p:first-of-type 选择属于其父元素的首个 <p> 元素的每个 <p> 元素。
p:last-of-type 选择属于其父元素的最后 <p> 元素的每个 <p> 元素。
p:only-of-type 选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。
p:only-child 选择属于其父元素的唯一子元素的每个 <p> 元素。
p:nth-child(2) 选择属于其父元素的第二个子元素的每个 <p> 元素。
:enabled :disabled 控制表单控件的禁用状态。
:checked 单选框或复选框被选中。
18.解释盒模型宽高值得计算方式,边界塌陷,负值作用,box-sizing概念?#
\1. 盒模型:IE 678 下(不添加doctype) 使用ie盒模型,宽度 = 边框 + padding + 内容宽度;
chrom、IE9+、(添加doctype) 使用标准盒模型, 宽度 = 内容宽度。
\2. box-sizing : 为了解决标准黑子和IE盒子的不同,CSS3增添了盒模型属性box-sizing,
content-box(默认),border-box 让元素维持IE传统盒子模型, inherit 继承 父盒子模型;
\3. 边界塌陷:块元素的 top 与 bottom 外边距有时会合并(塌陷)为单个外边距(合并后最大的外边
距),这样的现象称之为 外边距塌陷。
\4. 负值作用:负margin会改变浮动元素的显示位置,即使我的元素写在DOM的后面,我也能让它显示在最
前面。
19.如何实现浏览器内多个标签页之间的通信?#
调用localstorge、cookies等本地存储方式
20.解释下浮动和它的工作原理?清除浮动的方法#
浮动元素脱离文档流,不占据空间。浮动元素碰到包含它的边框或者浮动元素的边框停留。
1.使用空标签清除浮动。
这种方法是在所有浮动标签后面添加一个空标签 定义css clear:both. 弊端就是增加了无意义标签。
2.使用after伪对象清除浮动
该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要
清除浮动元素的伪对象中设置 height:0,否则该元素会比实际高出若干像素;
\#parent:after{
content:".";
height:0;
visibility:hidden;
display:block;
clear:both;
}
3.设置overflow为hidden或者auto
4.浮动外部元素
5.标签语义化
代码结构更加清晰
见名知意,没有基础的人也能知道这部分代码是干嘛的
方便团队开发维护,代码可读性更强
有利于SEO优化,爬虫依赖于标签来确定上下文关系
6.meta标签
meta标签提供关于html文档的元数据,不会显示在页面,但是对于机器是可读的,告诉浏览器怎么解析页
面,告诉搜索引擎关键字(SEO优化)
meta作用:告诉机器浏览器该如何解析该页面,描述这个页面的主要内容,可以设置服务器发送到浏览器的
http头部内容
charset="utf-8"设置页面使用的字符编码
viewport 设置视口,移动端的适配
7.css与javascript引入设置
script标签的引入一般放在body最后,这样避免脚本过大,加载时间长,导致页面长时间空白,这是因为渲
染进程与js进程是互斥的,脚本会阻塞页面的渲染,脚本之间的加载是同步进行的,按引入顺序执行,但是以
下两个属性会影响脚本执行与页面渲染的顺序
defer:不会阻塞渲染,这样即使放在header内部,也不会阻塞页面加载,不过js会先于document加载完
成,并且也不会影响脚本之间的执行顺序,按照引入顺序执行
async:与defer一样,都是解决阻塞渲染,但它是在document加载完成后才执行,并且它的执行顺序是按
照谁先加载完成执行谁,所以对于文件顺序有要求,存在前后依赖的不要使用它
8.HTML的块级元素,行内元素,行内块元素有哪些,区别是什么
块级元素:div,h1-h6,p,ul,ol,dl,li,hr,dt,dd,form,table
块元素独占一行
宽高生效
默认宽和父元素一样,内容撑开高度
margin,padding全部生效
行内元素:em,i,del,small,strong,ins,span,a
宽高不生效
左右margin生效上下不生效
在一行排列
大小靠内容撑开
padding都生效
行内块元素:img,input(表单元素,除去form)
在一行排列
宽高生效
margin,padding生效
9.CSS3有哪些新特性
border-radius圆角
border-image 边框图片
border-image: url() top right bottom left
border-width: top right bottom left
box-shadow盒子阴影: x,y,size,opcity
text-shadow文字阴影
linear-gradient 线性渐变
background: linear-gradient(to position , color,color,...,color)
radial-gradient 径向渐变
background: radial-gradient(shap size at position , color,color,...,color)
2D/3D转换 transform:rotate(旋转) scale(缩放) translate(位移)
@media媒体查询,根据屏幕宽度,设置,用来解决移动端适配,根据屏幕大小使相应的css生效
flex布局(弹性盒子)
10.实现元素隐藏
display:none 不占位,源码可见
opacity: 0 占位,源码可见,透明度0
visibility: hidden 占位,源码可见
position: top:-9999px,left:-9999px 利用定位将元素移出视窗
11.如何实现元素水平居中
行内元素:text-align:center
块元素: margin: 0 auto
position: left: 50%; transform: translate(-50%)
12.如何实现元素垂直居中
height = line-height
verticle-align: middle
position: top: 50%; transform: translate(0,-50%)
13.Position
static 默认
relative 相对定位,不脱标,相对于自身位置进行偏离,不影响元素本身特性,z-index提升层级
absolute 绝对定位,脱标,相对于已有定位的父元素进行偏离,都没有就相对于body进行偏离
fixed 固定定位,脱标,相对于视窗进行偏离
14.定位元素水平垂直居中
宽高固定 position: top:0,left:0,right:0,bottom:0,margin:auto
宽高固定 position:top: 50%, left: 50%, margin-left: -width/2px,margin-top: height/2px
dispaly: flex; justify-content: center,align-items: center(极力推荐)
position: left: 50%,top: 50%; transform: translate(-50%,-50%)
15.清除浮动
不清楚浮动会发生高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父
元素会发生高度塌陷)
clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式:
{clear:both;height:0;overflow:hidden;}
给浮动元素父级设置高度
父级同时浮动(需要给父级同级元素添加浮动)
父级设置成inline-block,其margin: 0 auto居中方式失效
给父级添加overflow:hidden 清除浮动方法
万能清除法 after伪类 清浮动(现在主流方法,推荐使用)
.float_div:after{
content:".";
clear:both;
display:block;
height:0;
overflow:hidden;
visibility:hidden;
}
.float_div{
zoom:1
}
16.css选择器有哪些,选择器的优先级
- id选择器
- 类选择器
- 属性选择器
- 伪类选择器
- 标签选择器
- 伪元素选择器
- 通配符选择器
优先级:内联样式 > ID选择器(100)> 类选择器(10) = 属性选择器 = 伪类选择器 > 元素选择器(1) =
关系选择器 = 伪元素选择器 > 通配符选择器(0)
!important
后代选择器选全部
子代选择器只选亲孩子
15.各种布局优缺点#
1. float 布局
优点: 比较简单,兼容性也比较好。只要清除浮动做的好,是没有什么问题的缺点:浮动元素是脱离文档
流,要做清除浮动,这个处理不好的话,会带来很多问题,比如高度塌陷等。
2. 绝对布局
优点:很快捷,设置很方便,而且也不容易出问题缺点:绝对定位是脱离文档流的,意味着下面的所有子
元素也会脱离文档流,这就导致了这种方法的有效性和可使用性是比较差的。
3. flex 布局
优点:简单快捷缺点:不支持 IE8 及以下
4. table布局
优点:实现简单,代码少缺点:当其中一个单元格高度超出的时候,两侧的单元格也是会跟着一起变高
的,而有时候这种效果不是我们想要的。
5. grid布局
跟 flex 相似。
16.html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分
HTML 和 HTML5?
**新特性:**
HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。
拖拽释放(Drag and drop) API
语义化更好的内容标签(header,nav,footer,aside,article,section)
音频、视频API(audio,video)
画布(Canvas) API
地理(Geolocation) API
本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
sessionStorage 的数据在浏览器关闭后自动删除
表单控件,calendar、date、time、email、url、search
新的技术webworker, websocket, Geolocation
**移除元素:**
纯表现的元素:basefont,big,center,font, s,strike,tt,u;
对可用性产生负面影响的元素:frame,frameset,noframes;
**h5新标签兼容:**
IE8/IE7/IE6支持通过document.createElement方法产生的标签,
可以利用这一特性让这些浏览器支持HTML5新标签,
当然最好的方式是直接使用成熟的框架、使用最多的是html5shim框架
```html
<!--[if lt IE 9]>
<script> src="http://html5shim.googlecode.com/svn/trunk/html5.js"</script>
<![endif]-->
如何区分:
DOCTYPE声明\新增的结构元素\功能元素
17. CSS3新增伪类举例:
p:first-of-type 选择属于其父元素的首个
元素的每个
元素。
p:last-of-type 选择属于其父元素的最后
元素的每个
元素。
p:only-of-type 选择属于其父元素唯一的
元素的每个
元素。
p:only-child 选择属于其父元素的唯一子元素的每个
元素。
p:nth-child(2) 选择属于其父元素的第二个子元素的每个
元素。
:enabled :disabled 控制表单控件的禁用状态。
:checked 单选框或复选框被选中。
18.解释盒模型宽高值得计算方式,边界塌陷,负值作用,box-sizing概念?
\1. 盒模型:IE 678 下(不添加doctype) 使用ie盒模型,宽度 = 边框 + padding + 内容宽度; chrom、
IE9+、(添加doctype) 使用标准盒模型, 宽度 = 内容宽度。
\2. box-sizing : 为了解决标准黑子和IE盒子的不同,CSS3增添了盒模型属性box-sizing,contentbox(默认),border-box 让元素维持IE传统盒子模型, inherit 继承 父盒子模型;
\3. 边界塌陷:块元素的 top 与 bottom 外边距有时会合并(塌陷)为单个外边距(合并后最大的外边
距),这样的现象称之为 外边距塌陷。
\4. 负值作用:负margin会改变浮动元素的显示位置,即使我的元素写在DOM的后面,我也能让它显示
在最前面。
19.如何实现浏览器内多个标签页之间的通信?
调用localstorge、cookies等本地存储方式
20.解释下浮动和它的工作原理?清除浮动的方法
浮动元素脱离文档流,不占据空间。浮动元素碰到包含它的边框或者浮动元素的边框停留。
1.使用空标签清除浮动。
这种方法是在所有浮动标签后面添加一个空标签 定义css clear:both. 弊端就是增加了无意义标签。
2.使用after伪对象清除浮动
该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须
为需要清除浮动元素的伪对象中设置 height:0,否则该元素会比实际高出若干像素;
#parent:after{
content:".";
height:0;
visibility:hidden;
display:block;
clear:both;
}
3.设置overflow为hidden或者auto
4.浮动外部元素
JS基础#
1.什么是闭包#
能够读取其他函数内部变量的函数。
或简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。
2.闭包的用途#
1、读取函数内部的变量
2、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。
3、方便调用上下文的局部变量。利于代码封装。
原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,因此f1也始终
存在内存中,不会在调用结束后,被垃圾回收机制回收。
3.闭包的缺点#
1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网
页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删
除。
2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,
把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时
一定要小心,不要随便改变父函数内部变量的值。
4.闭包实用场景#
https://juejin.cn/post/6844903619595075592
5. JS 有哪些数据类型?#
根据 JavaScript 中的变量类型传递方式,分为基本数据类型和引用数据类型两大类七种。
基本数据类型包括Undefined、Null、Boolean、Number、String、Symbol (ES6新增)六种。
引用数据类型只有Object一种,主要包括对象、数组和函数。
判断数据类型采用typeof操作符,有两种语法:
typeof 123;//语法一
const FG = 123;
typeof FG;//语法二
typeof(null) //返回 object;
null == undefined //返回true,因为undefined派生自null;
null === undefined //返回false。
6.基本数据类型和引用数据类型有什么区别?#
(1)两者作为函数的参数进行传递时:
基本数据类型传入的是数据的副本,原数据的更改不会影响传入后的数据。
引用数据类型传入的是数据的引用地址,原数据的更改会影响传入后的数据。
(2)两者在内存中的存储位置:
基本数据类型存储在栈中。
引用数据类型在栈中存储了指针,该指针指向的数据实体存储在堆中。
7.判断数据类型的方法有哪些?#
(1)利用typeof可以判断数据的类型;
(2)A instanceof B可以用来判断A是否为B的实例,但它不能检测 null 和 undefined;
(3)B.constructor == A可以判断A是否为B的原型,但constructor检测 Object与instanceof不一
样,还可以处理基本数据类型的检测。
不过函数的 constructor 是不稳定的,这个主要体现在把类的原型进行重写,在重写的过程中很有可能出
现把之前的constructor给覆盖了,这样检测出来的结果就是不准确的。
(4)Object.prototype.toString.call()
Object.prototype.toString.call() 是最准确最常用的方式。
8.浅拷贝与深拷贝有何区别?如何实现?#
浅拷贝只复制指向某个对象的指针,而不复制对象本身。浅拷贝的实现方式有:
(1)Object.assign():需注意的是目标对象只有一层的时候,是深拷贝;
(2)扩展运算符;
深拷贝就是在拷贝数据的时候,将数据的所有引用结构都拷贝一份。深拷贝的实现方式有:
(1)手写遍历递归赋值;
(2)结合使用JSON.parse()和JSON.stringify()方法。
9. let、const的区别是什么?#
let与const都是只在声明所在的块级作用域内有效。
let声明的变量可以改变,值和类型都可以改变,没有限制。
const 声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const a ;//报错,一旦声明变量,应该立即赋值!!
const b = 2;
b = 3//报错,因为定义常量之后不能成重新赋值!!
对于复合类型的变量,如数组和对象,变量名不指向数据,而是指向数据所在的地址。 const 命令只是
保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。
const names = [];
names = [1,2,3] //出错,因为变量names指向的地址不能发生改变,应始终指向[]所在的地址!!!
[1,2,3]与[]不是同一个地址
//不会报错,因为names指向的地址不变,改变的只是内部数据const names = [];
names[0] = 1
names[1] = 2
names[2] = 3
如果想让定义的对象或数组的内部数据也不能够修改和改变,可以使用object.freeze(names)进行冻
结,这样为对象添加新属性就不起作用。
除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
10. 什么是执行上下文和执行栈?#
变量或函数的执行上下文,决定了它们的行为以及可以访问哪些数据。每个上下文都有一个关联的变量对象,
而这个上下文中定义的所有变量和函数都存在于这个对象上(如DOM中全局上下文关联的便是window对象)。
每个函数调用都有自己的上下文。当代码执行流进入函数时,函数的上下文被推到一个执行栈中。在函数执行
完之后,执行栈会弹出该函数上下文,在其上的所有变量和函数都会被销毁,并将控制权返还给之前的执行上
下文。 JS的执行流就是通过这个执行栈进行控制的。
11.什么是作用域和作用域链?#
作用域可以理解为一个独立的地盘,可以理解为标识符所能生效的范围。作用域最大的用处就是隔离变
量,不同作用域下同名变量不会有冲突。ES6中有全局作用域、函数作用域和块级作用域三层概念。
当一个变量在当前块级作用域中未被定义时,会向父级作用域(创建该函数的那个父级作用域)寻找。
如果父级仍未找到,就会再一层一层向上寻找,直到找到全局作用域为止。这种一层一层的关系,就是
作用域链 。
12.作用域和执行上下文的区别是什么?#
1)函数的执行上下文只在函数被调用时生成,而其作用域在创建时已经生成;
2)函数的作用域会包含若干个执行上下文(有可能是零个,当函数未被调用时)。
13.this指向的各种情况都有什么?#
this的指向只有在调用时才能被确定,因为this是执行上下文的一部分。
(1)全局作用域中的函数:其内部this指向window:
var a = 1;
function fn(){
console.log(this.a)
}
fn() //输出1
(2)对象内部的函数:其内部this指向对象本身:
var a = 1;
var obj = {
a:2,
fn:function(){
console.log(this.a)
}
}
obj.fn() //输出2
(3)构造函数:其内部this指向生成的实例:
function createP(name,age){
this.name = name //this.name指向P
this.age = age //this.age指向P
}
var p = new createP("老李",46)
(4)由apply、call、bind改造的函数:其this指向第一个参数:
function add(c,d){
return this.a + this.b + c + d
}
var o = {a:1,b:2)
add.call(o,5,7) //输出15
(5)箭头函数:箭头函数没有自己的this,看其外层的是否有函数,如果有,外层函数的this就是内部
箭头函数的this,如果没有,则this是window。
14.如何改变this指针的指向?#
可以使用apply、call、bind方法改变this指向(并不会改变函数的作用域)。比较如下:
(1)三者第一个参数都是this要指向的对象,也就是想指定的上下文,上下文就是指调用函数的那
个对象(没有就指向全局window);
(2)apply和bind的第二个参数都是数组,call接收多个参数并用逗号隔开;
(3)apply和call只对原函数做改动,bind会返回新的函数(要生效还得再调用一次)。
15.如何理解同步和异步?#
同步:按照代码书写顺序一一执行处理指令的一种模式,上一段代码执行完才能执行下一段代码。
异步:可以理解为一种并行处理的方式,不必等待一个程序执行完,可以执行其它的任务。
JS之所以需要异步的原因在于JS是单线程运行的。常用的异步场景有:定时器、ajax请求、事件绑定。
16.JS是如何实现异步的?#
JS引擎是单线程的,但又能实现异步的原因在于事件循环和任务队列体系。
事件循环:
JS 会创建一个类似于 while (true) 的循环,每执行一次循环体的过程称之为 Tick。每次 Tick 的过程
就是查看是否有待处理事件,如果有则取出相关事件及回调函数放入执行栈中由主线程执行。待处理的
事件会存储在一个任务队列中,也就是每次 Tick 会查看任务队列中是否有需要执行的任务。
任务队列:
异步操作会将相关回调添加到任务队列中。而不同的异步操作添加到任务队列的时机也不同,如
onclick, setTimeout, ajax 处理的方式都不同,这些异步操作是由浏览器内核的 webcore 来执行的,浏
览器内核包含3种 webAPI,分别是 DOM Binding、network、timer模块。
onclick 由 DOM Binding 模块来处理,当事件触发的时候,回调函数会立即添加到任务队列中。
setTimeout 由 timer 模块来进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中。
ajax 由network 模块来处理,在网络请求完成返回之后,才将回调添加到任务队列中。
主线程:
JS 只有一个线程,称之为主线程。而事件循环是主线程中执行栈里的代码执行完毕之后,才开始执
行的。所以,主线程中要执行的代码时间过长,会阻塞事件循环的执行,也就会阻塞异步操作的执行。
只有当主线程中执行栈为空的时候(即同步代码执行完后),才会进行事件循环来观察要执行的事
件回调,当事件循环检测到任务队列中有事件就取出相关回调放入执行栈中由主线程执行。
17.什么是AJAX?如何实现?#
ajax是一种能够实现局部网页刷新的技术,可以使网页异步刷新。
ajax的实现主要包括四个步骤:
(1)创建核心对象XMLhttpRequest;
(2)利用open方法打开与服务器的连接;
(3)利用send方法发送请求;("POST"请求时,还需额外设置请求头)
(4)监听服务器响应,接收返回值。
ajax是一种能够实现局部网页刷新的技术,可以使网页异步刷新。
ajax的实现主要包括四个步骤:
(1)创建核心对象XMLhttpRequest;
(2)利用open方法打开与服务器的连接;
(3)利用send方法发送请求;("POST"请求时,还需额外设置请求头)
(4)监听服务器响应,接收返回值。
18.实现异步的方式有哪些?#
(1)回调函数模式:将需要异步执行的函数作为回调函数执行,其缺点在于处理复杂逻辑异步逻辑时,
会造成回调地狱(回调嵌套层数太多,代码结构混乱);
(2)事件监听模式:采用事件驱动的思想,当某一事件发生时触发执行异步函数,其缺点在于整个代码
全部得变为事件驱动模式,难以分辨主流程;
(3)发布订阅模式:当异步任务执行完成时发布消息给信号中心,其他任务通过在信号中心中订阅消息
来确定自己是否开始执行;
(4)Promise(ES6):Promise对象共有三种状态pending(初始化状态)、fulfilled(成功状态)、
rejected(失败状态)。
(5)async/await(ES7):基于Promise实现的异步函数;
(6)利用生成器实现。
19.怎么理解Promise对象?#
Promise对象有如下两个特点:
(1)对象的状态不受外界影响。Promise对象共有三种状态pending、fulfilled、rejected。状态值
只会被异步结果决定,其他任何操作无法改变。
(2)状态一旦成型,就不会再变,且任何时候都可得到这个结果。状态值会由pending变为
fulfilled或rejected,这时即为resolved。
Promise的缺点有如下三个缺点:
(1)Promise一旦执行便无法被取消;
(2)不可设置回调函数,其内部发生的错误无法捕获;
(3)当处于pending状态时,无法得知其具体发展到了哪个阶段。
Pomise中常用的方法有:
(1)Promise.prototype.then():Promise实例的状态发生改变时,会调用then内部的回调函数。
then方法接受两个参数(第一个为resolved状态时时执行的回调,第一个为rejected状态时时执行的回
调)
(2)Promise.prototype.catch():.then(null, rejection)或.then(undefined, rejection)的别名,用
于指定发生错误时的回调函数。
20.怎么理解宏任务,微任务???#
宏任务有:script(整体代码)、setTimeout、setInterval、I/O、页面渲染;
微任务有:Promise.then、Object.observe、MutationObserver。
执行顺序大致如下:
主线程任务——>宏任务——>微任务——>微任务里的宏任务——>.......——>直到任务全部完成
21.实现继承的方法有哪些???#
实现继承的方法有:
(1)class+extends继承(ES6)
//类模板
class Animal {
constructor(name){
this.name = name
}
}
//继承类
class Cat extends Animal{//重点。extends方法,内部用constructor+super
constructor(name) {
super(name);
//super作为函数调用时,代表父类的构造函数
}//constructor可省略
eat(){
console.log("eating")
}
}
(2)原型继承
//类模板
function Animal(name) {
this.name = name;
}
//添加原型方法
Animal.prototype.eat = function(){
console.log("eating")
}
function Cat(furColor){
this.color = color ;
};
//继承类
Cat.prototype = new Animal()//重点:子实例的原型等于父类的实例
(3)借用构造函数继承
function Animal(name){
this.name = name
}
function Cat(){
Animal.call(this,"CatName")//重点,调用父类的call方法
}
(4)寄生组合式继承(重点)
22.require/import之间的区别?#
(1)require是CommonJS语法,import是ES6语法;
(2)require只在后端服务器支持,import在高版本浏览器及Node中都可以支持;
(3)require引入的是原始导出值的复制,import则是导出值的引用;
(4)require时运行时动态加载,import是静态编译;
(5)require调用时默认不是严格模式,import则默认调用严格模式.
23.原型和原型链#
1、原型的概念
JavaScript的象中都包含了一个 [proto] 内部属性,这个属性所对应的就是自身的原型
2、原型链的概念
当一个对象调用自身不存在的属性/方法时,就会去自己 [proto] 关联的前辈 prototype 对象上去找,如
果没找到,就会去该 prototype 原型 [proto] 关联的前辈 prototype 去找。依次类推,直到找到属性/方
法或 undefined 为止。从而形成了所谓的“原型链”。
24.事件委托#
事件委托,又名事件代理。事件委托就是利用事件冒泡,就是把子元素的事件都绑定到父元素上。如果
子元素阻止了事件冒泡,那么委托也就没法实现了。
25.解释一下变量的提升#
变量的提升是JavaScript的默认行为,这意味着将所有变量声明移动到当前作用域的顶部,并且可以在声
明之前使用变量。初始化不会被提升,提升仅作用于变量的声明。
var x = 1
console.log(x + '——' + y) // 1——undefined
var y = 2
26. 如何理解高阶函数#
JavaScript中的一切都是对象,包括函数。我们可以将变量作为参数传递给函数,函数也是如此。我们调
用接受和或返回另一个函数称为高阶函数的函数。
27.如何区分声明函数和表达式函数#
// 声明函数
function hello() {
return "HELLO"
}
// 表达式函数
var h1 = function hello() {
return "HELLO"
}
两个函数将在不同的时期定义。在解析期间定义声明,在运行时定义表达式;因此,如果我们控制台打印
h1 ,它将显示 HELLO 。
28.解释原型继承是如何工作的#
JavaScript不是一种面向对象的友好编程语言,但它仍然使用继承的思想来实现依赖关系,并使用许多内
置函数使其灵活使用。了解原型继承的工作原理将使你很好地理解JavaScript知识,从而避免概念上的误
用。
最好在大脑中描绘一下JavaScript的整个机制,以了解原型继承。
HTTP#
1.什么是域名发散和域名收敛?#
1、域名发散
为了突破浏览器对于同一域名并发请求数的限制,http 静态资源采用多个子域名,通常为2~4个。
目的是充分利用现代浏览器的多线程并发下载能力。
2、域名收敛
域名收敛和域名发散正好相反:就是将静态资源只放在一个域名下面,而非发散情况下的多个域名下。
主要是为了适应移动端的发展需求。
2.为什么浏览器要做并发限制呢?#
1.以前网速慢、服务器硬件设备差、负载能力差,容易崩溃,所以要对最大并发数进行限制
3.什么是 DDOS 攻击#
分布式拒绝服务攻击(Distributed denial of service attack)
向目标系统同时提出数量庞大的服务请求。
4.DDOS 攻击方式#
1.通过使网络过载来干扰甚至阻断正常的网络通讯;
2.通过向服务器提交大量请求,使服务器超负荷;
3.阻断某一用户访问服务器;
4.阻断某服务与特定系统或个人的通讯。
5.如何应对 DDOS 攻击#
黑名单
DDOS 清洗:对用户请求数据进行实时监控,及时发现DOS攻击等异常流量,在不影响正常业务开展的
情况下清洗掉这些异常流量。
CDN 加速
高防服务器:高防服务器主要是指能独立硬防御 50Gbps 以上的服务器,能够帮助网站拒绝服务攻击,
定期扫描网络主节点
6.http请求过程#
1.对www.abc.com这个网址进行DNS域名解析,得到对应的IP地址
2.根据这个IP,找到对应的服务器,发起TCP的三次握手
3.建立TCP连接后发起HTTP请求
4.服务器响应HTTP请求,浏览器得到html代码
5.浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)(先得到html代码,才能去找
这些资源)
6.浏览器对页面进行渲染呈现给用户
7.服务器关闭关闭TCP连接
7.DNS 域名如何解析的?#
DNS域名解析采用的是递归查询的方
先去找DNS缓存->缓存找不到就去找根域名服务器->根域名又会去找下一级,递归查找之后,找到了,
给我们的web浏览器。
1.浏览器首先搜索自身的DNS缓存,看缓存中是否有 www.abc.com 这个域名,有而且没有过期的话,
解析结束。
2.如果浏览器自身的缓存中没有找到,则会搜索操作系统自身的DNS缓存,如果找到且没有过期则停止
搜索,解析到此结束。
3.如果在操作系统的DNS缓存中也没有找到,那么尝试读取hosts文件,有则解析成功,解析到此结束。
4.如果在hosts文件中也没有找到,浏览器会发起一个DNS(Domain Name System:域名服务协议)
系统调用,向本地配置的首选DNS服务器发起域名解析请求 (递归请求)
1.运营商的DNS服务器首先查找自身的缓存,如果能找到且没有过期则解析成功。
2.如果没有找到,则运营商的DNS代我们的浏览器发起迭代DNS解析请求。
3.运营商DNS首先会查找根域DNS的IP地址(这个DNS服务器内置13台根DNS域服务器的IP地址),找
到根域的DNS地址,就会向其发起请求((问一下www.abc.com这个域名的ip地址是多少啊?))。根
域发现这是一个com域(顶级域)的域名,于是返回com域的IP地址,然后运营商的DNS就得到com域
的IP地址。
4.运营商的DNS得到com域的IP地址之后又向com域的IP地址发起地址请求(问一下www.abc.com这个
域名的IP地址是多少啊?)。com域这台服务器告诉运营商的DNS我不知道www.abc.com这个域名的IP
地址,但是我知道abc.com这个域名的DNS地址,你去找它吧。
5.运营商的DNS又向abc.com这个域名的DNS地址发起请求,(问一下www.abc.com这个域名的IP地址
是多少?)
6.这个时候abc.com域的DNS服务器在本地查找。
7.把找到的结果发给运营商的DNS服务器,这个时候运营商的DNS服务器就拿到了www.abc.com对应的
IP地址,并返回给Windows系统内核,内核就把这个结果返回给浏览器,最终浏览器得到这个IP地址,
进行下一步动作。
8.TCP三次握手#
1.客服端首先发送一个连接试探。
2.服务器监听到连接请求报文后,如果同意建立连接,则向Client发送确认。
3.Client收到确认后还需要再次发送确认,同时携带要发送给Server的数据。
9.为什么要三次握手?#
1.验证服务端和客户端是否遵循TCP/IP协议
2.为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
10.为什么HTTP协议要基于TCP来实现?#
TCP是一个端到端的可靠的面相连接的协议,HTTP基于传输层TCP协议不用担心数据传输的各种问题
(当发生错误时,会重传)
11.什么是面相连接协议?面向无链接协议又是什么?#
1. 面相连接协议定义
通信双方在通信时,要事先建立好一条通信线路(虚拟的)。
其过程有建立连接、维护连接、释放(断开)连接三个过程。
TCP是面向连接的
2. 面向无链接协议定义
与面向连接相对,面向无连接是指通信双方不需要事先建立通信线路,而是把每个带有目的地址的报文
分组送到线路上,由系统自主选定线路进行传输。
面向无连接只有“传送数据”的过程。
UDP是面向无连接的
12.说到三次握手,那在说下四次挥手吧?#
1.客户端进程发出连接释放报文,并且停止发送数据。
2.服务器收到连接释放报文,发出确认报文,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。
(客户端向服务器方向释放了,但是服务器发送数据,客户端依然要接受)
3.客户端收到服务器的确认请求后,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接
释放报文(在这之前还需要接受服务器发送的最后的数据)。
4.服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,服务器就进入了LAST-ACK(最后确
认)状态,等待客户端的确认。
5.客户端收到服务器的连接释放报文后,必须发出确认,客户端就进入了TIME-WAIT(时间等待)状
态。
6.服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的
TCP连接。(服务器结束TCP连接的时间要比客户端早一些。)
13.为什么要四次挥手#
TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,
当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全
部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示
它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文
段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此
就会愉快的中断这次TCP连接。
14.为什么建立连接是三次握手,关闭连接确是四次挥手呢?#
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报
文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己
也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报
文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。
15.如果已经建立了连接,但是客户端突然出现故障了怎么办?#
TCP还设有一个保活计时器。但是客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务
器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到
客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报
文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
16.http请求方式有哪些?#
1.GET:请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据。
2.HEAD:请求一个与GET请求的响应相同的响应,但没有响应体。
3.POST:将实体提交到指定的资源。
4.PUT:请求有效载荷替换目标资源的所有当前表示。
5.DELETE:删除指定的资源。
6.OPTIONS:用于描述目标资源的通信选项。
7.PATCH:对资源应用部分修改。
8.CONNECT:建立一个到由目标资源标识的服务器的隧道。
9.TRACE:沿着到目标资源的路径执行一个消息环回测试。
17.常用的请求状态码?#
1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码。
代码 说明
http状态码 100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
http状态码 101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
2xx (成功)
表示成功处理了请求的状态代码。
代码 说明
http状态码 200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
http状态码 201 (已创建) 请求成功并且服务器创建了新的资源。
http状态码 202 (已接受) 服务器已接受请求,但尚未处理。
http状态码 203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
http状态码 204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
http状态码 205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
http状态码 206 (部分内容) 服务器成功处理了部分 GET 请求。
3xx (重定向)
表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
代码 说明
http状态码 300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
http状态码 301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
http状态码 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
http状态码 303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
http状态码 304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
http状态码 305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
http状态码 307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
4xx(请求错误)
这些状态代码表示请求可能出错,妨碍了服务器的处理。
代码 说明
http状态码 400 (错误请求) 服务器不理解请求的语法。
http状态码 401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
http状态码 403 (禁止) 服务器拒绝请求。
http状态码 404 (未找到) 服务器找不到请求的网页。
http状态码 405 (方法禁用) 禁用请求中指定的方法。
http状态码 406 (不接受) 无法使用请求的内容特性响应请求的网页。
http状态码 407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
http状态码 408 (请求超时) 服务器等候请求时发生超时。
http状态码 409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
http状态码 410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
http状态码 411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
http状态码 412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
http状态码 413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
http状态码 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
http状态码 415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
http状态码 416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
http状态码 417 (未满足期望值) 服务器未满足”期望”请求标头字段的要求。
5xx(服务器错误)
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
代码 说明
http状态码 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
http状态码 501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
http状态码 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
http状态码 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
http状态码 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
http状态码 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
18.TCP和UDP的区别以及应用场景#
1.UDP#
1.UDP在传输层上
2.是面向无连接的
3.不需要建立可靠的连接
4.是面向报文
5.限制就是发送一些比较小的包文件,而且没有错误处理机制。包没了就是没了。可以做一些处理,比
如超时重发
6.一对一、一对多、多对一、多对多通信
7.适用于实时应用
2.TCP#
1.TCP在传输层上
2.是TCP是面向连接的
3.可以互相信任的进行数据发送,这样的保密性强一些
4.面向字节流
5.一对一通信
6.适用于可靠传输的应用
3.应用场景
19.GET和POST的区别#
#这个问题。我相信只要你说你做过接口测试,基本上都被问到过。
简单来说:GET产生一个TCP数据包,POST产生两个TCP数据包
严格的说:对于GET方式的请求,游览器会把http header和data一并发送出去,服务器响应200
(返回数据);
而对于POST请求。游览器先发送header,服务器响应100 continue,游览器再发送data,服务器
响应200 ok(返回数据)
注:千万别说什么POST比GET安全什么的。这样一下子面试官就知道你的底子了。
20.cookies机制和session机制的区别:#
1、cookies数据保存在客户端。session数据保存在服务端
2、cookies可以减轻服务器压力,但是不安全,容易进行cookies欺骗
3、session安全一点,但是占用服务器资源。
21.HTTP、状态码:#
200:成功
302:重定向
404:请求失败,请求希望得到的资源违背在服务器发现。(只要不是新手写的demo,一般404都
是你路径写错了,或者未区分大小写啥的)
502:无效的响应(基本上就是Tomcat没启好)
400:请求没有进入到后台服务里(一般都是前端的锅)
22.Internet采用哪种网络协议?该协议的主要层次结构?#
TCP/IP协议(Transmission Control Protocol/Internet Protocol)叫做传输控制/网际协议,又叫网络通讯
协议,这个协议是Internet国际互联网络的基础。
TCP/IP是用于计算机通信的一组协议,我们通常称它为TCP/IP协议族。
TCP/IP是网络中使用的基本的通信协议。虽然从名字上看TCP/IP包括两个协议,传输控制协议(TCP)和网
际协议(IP),但TCP/IP实际上是一组协议,它包括TCP、IP、UDP、ICMP、RIP、TELNET、FTP、
SMTP、ARP、TFTP等许多协议,这些协议一起称为TCP/IP协议。
TCP/IP由四个层次组成:数据链路层、网络层、传输层、应用层。
数据链路层
这是TCP/IP软件的最低层,负责接收IP数据报并通过网络发送,或者从网络上接收物理帧,抽出IP数据
报,交给IP层。
网络层
负责相邻计算机之间的通信。其功能包括三方面:
a、处理来自传输层的分组发送请求,收到请求后,将分组装入IP数据报,填充报头,选择去往信宿机的
路径,然后将数据报发往适当的网络接口。
b、处理输入数据报:首先检查其合法性,然后进行寻径–假如该数据报已到达信宿机,则去掉报头,将
剩下部分交给适当的传输协议;假如该数据报尚未到达信宿,则转发该数据报。
c、处理路径、流控、拥塞等问题。
传输层
提供应用程序间的通信。其功能包括:
a、格式化信息流;
b、提供可靠传输。为实现后者,传输层协议规定接收端必须发回确认,并且假如分组丢失,必须重新发
送。
应用层
向用户提供一组常用的应用程序,比如电子邮件、文件传输访问、远程登录等。远程登录TELNET使用
TELNET协议提供在网络其它主机上注册的接口。TELNET会话提供了基于字符的虚拟终端。文件传输访
问FTP使用FTP协议来提供网络内机器间的文件拷贝功能。
OSI七层模型与TCP/IP协议的对应关系。
OSI中的层 功能 TCP/IP协议族
应用层 文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet
表示层 数据格式化,代码转换,数据加密 没有协议
会话层 解除或建立与别的接点的联系 没有协议
传输层 提供端对端的接口 TCP,UDP
网络层 为数据包选择路由 IP,ICMP,RIP,OSPF,BGP,IGMP
数据链路层 传输有地址的帧以及错误检测功能 SLIP,CSLIP,PPP,ARP,RARP,MTU
物理层 以二进制数据形式在物理媒体上传输数据
TCP/IP协议中一些常用协议英文名:
TCP(Transmission Control Protocol)传输控制协议
IP(Internet Protocol)网际协议
UDP(User Datagram Protocol)用户数据报协议
ICMP(Internet Control Message Protocol)互联网控制信息协议
SMTP(Simple Mail Transfer Protocol)简单邮件传输协议
SNMP(Simple Network manage Protocol)简单网络管理协议
FTP(File Transfer Protocol)文件传输协议
ARP(Address Resolation Protocol)地址解析协议
Internet物理地址和IP地址转换采用什么协议?
ARP (Address Resolution Protocol)(地址解析协议)。
23.IP地址的编码分为哪俩部分?#
IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些
是主机位。
24.TCP/IP通信建立的过程怎样,端口有什么作用?#
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
位码即tcp标志位,有6种标示:
SYN(synchronous建立联机)
ACK(acknowledgement 确认)
PSH(push传送)
FIN(finish结束)
RST(reset重置)
URG(urgent紧急)
Sequence number(顺序号码)
Acknowledge number(确认号码)
客户端TCP状态迁移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服务器TCP状态迁移:
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
各个状态的意义如下:
LISTEN - 侦听来自远方TCP端口的连接请求;
SYN-SENT -在发送连接请求后等待匹配的连接请求;
SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认;
ESTABLISHED- 代表一个打开的连接,数据可以传送给用户;
FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
FIN-WAIT-2 - 从远程TCP等待连接中断请求;
CLOSE-WAIT - 等待从本地用户发来的连接中断请求;
CLOSING -等待远程TCP对连接中断的确认;
LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认;
TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认;
CLOSED - 没有任何连接状态;
TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接,如图1所示。
(1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等
待服务器B确认。
(2)第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN
包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
(3)第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此
包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
确认号:其数值等于发送方的发送序号 +1(即接收方期望接收的下一个序列号)。
TCP的包头结构:
第一次握手:
客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口,以及初始序号X,保存在包
头的序列号(Sequence Number)字段里。
第二次握手:
服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号(Acknowledgement
Number)设置为客户的I S N加1以.即X+1。
第三次握手.
客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确
定字段中发送给对方.并且在数据段放写ISN的+1
关闭连接:
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任
务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个
TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关
闭。
CP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动
发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占
用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。
深入理解TCP连接的释放:
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务
后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP
连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
TCP协议的连接是全双工连接,一个TCP连接存在双向的读写通道。
简单说来是 “先关读,后关写”,一共需要四个阶段。以客户机发起关闭连接为例:
1.服务器读通道关闭
2.客户机写通道关闭
3.客户机读通道关闭
4.服务器写通道关闭
关闭行为是在发起方数据发送完毕之后,给对方发出一个FIN(finish)数据段。直到接收到对方发送的
FIN,且对方收到了接收确认ACK之后,双方的数据通信完全结束,过程中每次接收都需要返回确认数据
段ACK。
详细过程:
第一阶段 客户机发送完数据之后,向服务器发送一个FIN数据段,序列号为i;
1.服务器收到FIN(i)后,返回确认段ACK,序列号为i+1,关闭服务器读通道;
2.客户机收到ACK(i+1)后,关闭客户机写通道;
(此时,客户机仍能通过读通道读取服务器的数据,服务器仍能通过写通道写数据)
第二阶段 服务器发送完数据之后,向客户机发送一个FIN数据段,序列号为j;
3.客户机收到FIN(j)后,返回确认段ACK,序列号为j+1,关闭客户机读通道;
4.服务器收到ACK(j+1)后,关闭服务器写通道。
这是标准的TCP关闭两个阶段,服务器和客户机都可以发起关闭,完全对称。
FIN标识是通过发送最后一块数据时设置的,标准的例子中,服务器还在发送数据,所以要等到发送完的
时候,设置FIN(此时可称为TCP连接处于半关闭状态,因为数据仍可从被动关闭一方向主动关闭方传
送)。如果在服务器收到FIN(i)时,已经没有数据需要发送,可以在返回ACK(i+1)的时候就设置FIN(j)标
识,这样就相当于可以合并第二步和第三步。
TCP的TIME_WAIT和Close_Wait状态
除了ESTABLISHED,可以看到连接数比较多的几个状态是:FIN_WAIT1, TIME_WAIT, CLOSE_WAIT,
SYN_RECV和LAST_ACK;下面的文章就这几个状态的产生条件、对系统的影响以及处理方式进行简单描
述。
下面看下大家一般比较关心的三种TCP状态:
SYN_RECV : 服务端收到建立连接的SYN没有收到ACK包的时候处在SYN_RECV状态。有两个相关系统配
置:
CLOSE_WAIT: 发起TCP连接关闭的一方称为client,被动关闭的一方称为server。被动关闭的server收到
FIN后,但未发出ACK的TCP状态是CLOSE_WAIT。出现这种状况一般都是由于server端代码的问题,如
果你的服务器上出现大量CLOSE_WAIT,应该要考虑检查代码。
TIME_WAIT: 根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入
TIME_WAIT状态。TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分
钟,即240秒。TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短连接的服务
器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的socket,
甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,停
止服务。
为什么需要TIME_WAIT?TIME_WAIT是TCP协议用以保证被重新分配的socket不会受到之前残留的延迟
重发报文影响的机制,是必要的逻辑保证。
为了方便描述,我给这个TCP连接的一端起名为Client,给另外一端起名为Server。上图描述的是Client
主动关闭的过程,FTP协议中就这样的。如果要描述Server主动关闭的过程,只要交换描述过程中的
Server和Client就可以了,HTTP协议就是这样的。
描述过程:
Client调用close()函数,给Server发送FIN,请求关闭连接;Server收到FIN之后给Client返回确认ACK,
同时关闭读通道(不清楚就去看一下shutdown和close的差别),也就是说现在不能再从这个连接上读
取东西,现在read返回0。此时Server的TCP状态转化为CLOSE_WAIT状态。
Client收到对自己的FIN确认后,关闭 写通道,不再向连接中写入任何数据。
接下来Server调用close()来关闭连接,给Client发送FIN,Client收到后给Server回复ACK确认,同时
Client关闭读通道,进入TIME_WAIT状态。
Server接收到Client对自己的FIN的确认ACK,关闭写通道,TCP连接转化为CLOSED,也就是关闭连
接。
Client在TIME_WAIT状态下要等待最大数据段生存期的两倍,然后才进入CLOSED状态,TCP协议关闭连
接过程彻底结束。
以上就是TCP协议关闭连接的过程,现在说一下TIME_WAIT状态。
从上面可以看到,主动发起关闭连接的操作的一方将达到TIME_WAIT状态,而且这个状态要保持
Maximum Segment Lifetime的两倍时间。为什么要这样做而不是直接进入CLOSED状态?
原因有二:
一、保证TCP协议的全双工连接能够可靠关闭
二、保证这次连接的重复数据段从网络中消失
先说第一点,如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server
没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED
了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错
误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要
求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对
方收到ACK,最后正确的关闭连接。
再说第二点,如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与
刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发
生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次
连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连
接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个
延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在
TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
25.IP组播有那些好处?#
Internet上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧消耗和网络拥挤问
题。组播是一种允许一个或多个发送者(组播源)发送单一的数据包到多个接收者(一次的,同时的)的网络
技术。组播可以大大的节省网络带宽,因为无论有多少个目标地址,在整个网络的任何一条链路上只传
送单一的数据包。所以说组播技术的核心就是针对如何节约网络资源的前提下保证服务质量。
HTTP2 && HTTP缓存#
1.http/2项目设定目标#
1.页面加载时间 (PLT) 减少 50%。
2.无需网站作者修改任何内容。
3.将部署复杂性降至最低,无需变更网络基础设施。
4.与开源社区合作开发此新协议。
5.收集真实性能数据,验证实验性协议是否有效。
2.http/2特性#
1. 二进制分帧层
HTTP/2 所有性能增强的核心在于新的二进制分帧层,它定义了如何封装 HTTP 消息并在客户端与服务器
之间传输。
2. 多路复用(请求与响应复用)
HTTP/2 中新的二进制分帧层突破了这些限制,实现了完整的请求和响应复用:客户端和服务器可以将
HTTP 消息分解为互不依赖的帧,然后交错发送,最后再在另一端把它们重新组装起来。
3. 数据流优先级
将 HTTP 消息分解为很多独立的帧之后,我们就可以复用多个数据流中的帧,客户端和服务器交错发送
和传输这些帧的顺序就成为关键的性能决定因素。 为了做到这一点,HTTP/2 标准允许每个数据流都有
一个关联的权重和依赖关系:
可以向每个数据流分配一个介于 1 至 256 之间的整数。
每个数据流与其他数据流之间可以存在显式依赖关系。
4. 每个来源一个连接
每个数据流都拆分成很多帧,而这些帧可以交错,还可以分别设定优先级。 因此,所有 HTTP/2 连接都
是永久的,而且仅需要每个来源一个连接,随之带来诸多性能优势。
5. 流控制
流控制是一种阻止发送方向接收方发送大量数据的机制,以免超出后者的需求或处理能力:发送方可能
非常繁忙、处于较高的负载之下,也可能仅仅希望为特定数据流分配固定量的资源。
6. 服务器推送
HTTP/2 新增的另一个强大的新功能是,服务器可以对一个客户端请求发送多个响应。 换句话说,除了
对最初请求的响应外,服务器还可以向客户端推送额外资源,而无需客户端明确地请求。
7.标头压缩
每个 HTTP 传输都承载一组标头,这些标头说明了传输的资源及其属性。
HTTP/2 使用 HPACK 压缩格式压缩请求和响应标头元数据,这种格式采用两种简单但是强大的技术:
这种格式支持通过静态霍夫曼代码对传输的标头字段进行编码,从而减小了各个传输的大小。
这种格式要求客户端和服务器同时维护和更新一个包含之前见过的标头字段的索引列表(换句话
说,它可以建立一个共享的压缩上下文),此列表随后会用作参考,对之前传输的值进行有效编
码。
3.什么是缓存?又有什么用?#
定义:缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。
作用:
1.可以显著提高网站和应用程序的性能。
2.减少了等待时间和网络流量
3.减少了显示资源表示形式所需的时间。
4.是页面更加响应性。
5.缓解服务器端压力,提升性能。
4.你知道有哪些缓存方式吗?#
1.浏览器缓存
2.代理缓存
3.网关缓存
4.CDN缓存
5.反向代理缓存
5.缓存位置#
Service Worker
Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、
如何匹配缓存、如何读取缓存,并且缓存是持续性的。
Memory Cache
读取高效,但是持续性很短,一旦关闭 Tab 页面,内存中的缓存也就被释放了。
Disk Cache
读取速度慢,容量和存储时效性上有优势,
Push Cache
读取速度慢,容量和存储时效性上有优势,
6.http缓存怎样生效的?#
http缓存分为强制缓存和协商缓存
1. 强制缓存
强制缓存就是文件直接从缓存中获取,不需要发送请求
2. 协商缓存
协商缓存意思是文件已经被缓存了,但是否从缓存中读取是需要和服务器进行协商,具体如何协商
要看请求头/响应头的字段设置。
协商缓存还是会发送请求的。
3. 强缓存-Cache-Control
Cache-Control 通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。
4. 缓存请求指令
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: only-if-cached
2. 缓存响应指令
Cache-control: must-revalidate
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: public
Cache-control: private
Cache-control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-control: s-maxage=<seconds>
3. 指令解释
4.协商缓存生效过程
1. 浏览器第一次请求:
7.HTTP2的伪头字段#
伪头部字段是http2内置的几个特殊的以”:”开始的 key,用于替代HTTP/1.x中请求行/响应行中的信
息,比如请求方法,响应状态码等
1. :method 目标URL模式部分(请求)
2. :scheme 目标URL模式部分(请求)
3. :authority 目标RUL认证部分(请求)
4. :path 目标URL的路径和查询部分(绝对路径 产生式和一个跟着"?"字符的查询产生式)。 (请求)
5. :status 响应头中的HTTP状态码部分(响应)
8.HTTP 2:服务器推送#
HTTP 2 新增的另一个强大的新功能是,服务器可以对一个客户端请求发送多个响 应。 换句话说,
除了对最初请求的响应外,服务器还可以向客户端推送额外资源,而无需客户端明确地请求。
HTTP 2 打破了严格的请求-响应语义,支持一对多和服务器发起的推送工作流
服务器已经知道客户端下一步要请求什么资源,这时候服务器推送即可派上用场。
推送资源可以进行以下处理:
1. 由客户端缓存
2. 在不同页面之间重用
3. 与其他资源一起复用
4. 由服务器设定优先级
5. 被客户端拒绝
9.队首阻塞问题#
HTTP/1.1 和 HTTP/2 都存在队头阻塞问题(Head of line blocking)
HTTP/1.1 的队头阻塞。一个 TCP 连接同时传输 10 个请求,其中第 1、2、3 个请求已被客户端接
收,但第 4 个请求丢失,那么后面第 5 - 10 个请求都被阻塞,需要等第 4 个请求处理完毕才能被处
理,这样 就浪费了带宽资源。
HTTP/2 的多路复用虽然可以解决“请求”这个粒度的阻塞,但 HTTP/2 的基础 TCP 协议本身却也存
在着队头阻塞的问题。
由于 HTTP/2 必须使用 HTTPS,而 HTTPS 使用的 TLS 协议也存在队 头阻塞问题。
队头阻塞会导致 HTTP/2 在更容易丢包的弱网络环境下比 HTTP/1.1 更慢。
那 QUIC 解决队头阻塞问题的的方法:
1. QUIC 的传输单元是 Packet,加密单元也是 Packet,整个加密、 传输、解密都基于 Packet,这样
就能避免 TLS 的队头阻塞问题;
2. QUIC 基于 UDP,UDP 的数据包在接收端没有处理顺序,即使中间 丢失一个包,也不会阻塞整条
连接,其他的资源会被正常处理。
10.Transport头域#
Connection: close(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不
要等待本次连接的后续请求了) keepalive(告诉WEB服务器或者代理服务器,在完成本次请求的
响应后,保持连接,等待本次连接的后续请求)
Host:指定被请求资源的Internet主机和端口号
11.时效缓存(强制缓存)#
Cache-Control (低版本浏览器用的是Expires,了解即可)
是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
private:
客户端可以缓存
public:
客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的)
max-age=xxx: 缓存的内容将在 xxx 秒后失效
no-cache:
需要使用对比缓存来验证缓存数据
no-store:
所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多
越好,so...基本上和它说886)
12.非时效缓存(对比缓存,用的是标识):#
他用的不是时效时间max-age
第一次请求的时候,返回给客户端数据和缓存的信息,也就是一个特定的缓存标识
客户端把这个缓存标识放到缓存数据库
再次请求时 客户端先把缓存标识也一起发给服务端,进行对比
客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态
码,通知客户端比较成功,可以使用缓存数据。
13.两种缓存标识#
Etag (唯一标识)优先级更高
Last-Modified/If-Modified-Since 返回给客户端最后这个资源的修改时间,优先级没有Etag高
对比缓存标识生效不生效时,状态码200,服务端返回body和header
在对比缓存标识生效时,状态码为304,并且报文大小和请求时间大大减少。
原因是,服务端在进行标识比较后,只返回header部分,通过状态码通知客户端使用缓存,不再需要将
报文主体部分返回给客户端。
14.Service Worker#
比如页面引入了一个 JQuery,对于页面来说这个脚本就是一个工具库,基本上是不会发生变化的,对于
这种资源可以将它的缓存时间设置得长一点,比如如下这个地址的脚本:
是一个注册在指定源和路径下的事件驱动 worker ;特点是:
运行在 worker 上下文,因此它不能访问 DOM ;
独立于主线程之外,不会造成阻塞;
设计完全异步,所以同步 API (如 XHR 和 localStorage )不能在 Service Worker 中使用;
最后处于安全考虑,必须在 HTTPS 环境下才可以使用;
说了这么多特点,那它和缓存有啥关系?其实它有一个功能就是离线缓存: Service Worker Cache ;
区别于浏览器内部的 memory cache 和 disk cache ,它允许我们自己去操控缓存,具体操作过程可
以参看 Using_Service_Workers;通过 Service Worker 设置的缓存会出现在浏览器开发者工具
Application 面板下的 Cache Storage 中。
15.memory cache#
是浏览器内存中的缓存,相比于 disk cache 它的特点是读取速度快,但容量小,且时效性短,一旦浏
览器 tab 页关闭, memory cache 就将被清空。 memory cache 会自动缓存所有资源嘛?答案肯定是
否定的,当 HTTP 头设置了 Cache-Control: no-store 的时候或者浏览器设置了 Disabled cache
就无法把资源存入内存了,其实也无法存入硬盘。当从 memory cache 中查找缓存的时候,不仅仅会去
匹配资源的 URL ,还会看其 Content-type 是否相同。
16.disk cache#
也叫 HTTP cache 是存在硬盘中的缓存,根据 HTTP 头部的各类字段进行判定资源的缓存规则,比如是
否可以缓存,什么时候过期,过期之后需要重新发起请求吗?相比于 memory cache 的 disk cache
拥有存储空间时间长等优点,网站中的绝大多数资源都是存在 disk cache 中的。
浏览器如何判断一个资源是存入内存还是硬盘呢?关于这个问题,网上说法不一,不过比较靠谱的
观点是:对于大文件大概率会存入硬盘中;当前系统内存使用率高的话,文件优先存入硬盘。
缓存按照缓存位置划分,其实还有一个 HTTP/2 的内容 push cache ,由于目前国内对 HTTP/2 应用
还不广泛,且网上对 push cache 的知识还不齐全,所以本篇不打算介绍这块,感兴趣的可以阅读这篇
文章:HTTP/2 push is tougher than I thought
https#
1.https的访问过程#
1.客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
2.Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
3.客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
4.客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并
传送给网站。
5.Web服务器利用自己的私钥解密出会话密钥。
6.Web服务器利用会话密钥加密与客户端之间的通信。
详细解释:
1. 客户端发起HTTPS请求
用户在浏览器里输入一个https网址,然后连接到server的443端口。
2.服务端的配置
就是指上述提到的数字证书;
3.传送证书
Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
4.客户端解析证书
客户端会对证书进行判断,验证公钥是否有效,存在问题弹出会警告;若没有问题,生成一个随机值
(私钥),然后用证书继续进行加密;
5.传送加密信息
客户端将上加密后的随机值(私钥)提供给服务端,服务端会对其进行解密;
6.服务端解密信息
服务端解密后得到随机值(私钥),然后把内容通过该值进行对称加密。对称加密就是指把要返回的信
息和随机值(私钥)混合加密,这样除非知道随机值(私钥),不然无法获取数据。
7.传输加密后的信息
继续将加密后的信息传递给客户端;
8.客户端解密信息
客户端用之前生成的私钥(随机值)解密服务端传过来的信息,于是获取了解密后的内容。
2.https的优缺点?#
1. 优点#
1.正确发送数据到客户端
使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器
2.更安全
HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防
止数据在传输过程中不被窃取、改变,确保数据的完整性
3.增加中间人攻击的成本
HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
4.搜索排名更高
谷歌在2014跳转搜索算法,采用HTTPS加密的网站在搜索结果中的排名将会更高
百度也在2018年发布百度对HTTPS站点的扶持态度,表明HTTPS将作为优质特征之一影响搜索排序。
2、缺点#
1.页面渲染更耗时间
因为SSL的缘故,HTTPS协议握手阶段比较费时,会使页面的加载时间延长近50%;
2.成本增加
SSL证书需要花钱,功能越强大的证书费用越高;
3.HTTPS连接缓存不如HTTP高效
HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
4.SSL证书通常需要绑定IP
SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
5.有局限性
HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作
用。最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间
人攻击一样可行。
3.https如何进行性能优化?#
1.https访问速度优化
1.设置HSTS
服务端返回一个 HSTS 的 http header,浏览器获取到 HSTS 头部之后,在一段时间内,不管用户输入w
ww.baidu.com还是http://www.baidu.com,都会默认将请求内部跳转成https://www.baidu.com。
2.Session resume
Session Resume 顾名思义就是复用 Session,实现简化握手。
#### 1.https的访问过程
1.客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
2.Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
3.客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
4.客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给
网站。
5.Web服务器利用自己的私钥解密出会话密钥。
6.Web服务器利用会话密钥加密与客户端之间的通信。
##### 详细解释:
1. 客户端发起HTTPS请求
用户在浏览器里输入一个https网址,然后连接到server的443端口。
2.服务端的配置
就是指上述提到的数字证书;
3.传送证书
Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
4.客户端解析证书
客户端会对证书进行判断,验证公钥是否有效,存在问题弹出会警告;若没有问题,生成一个随机值(私
钥),然后用证书继续进行加密;
5.传送加密信息
客户端将上加密后的随机值(私钥)提供给服务端,服务端会对其进行解密;
6.服务端解密信息
服务端解密后得到随机值(私钥),然后把内容通过该值进行对称加密。对称加密就是指把要返回的信息和随
机值(私钥)混合加密,这样除非知道随机值(私钥),不然无法获取数据。
7.传输加密后的信息
继续将加密后的信息传递给客户端;
8.客户端解密信息
客户端用之前生成的私钥(随机值)解密服务端传过来的信息,于是获取了解密后的内容。
### 2.https的优缺点?
#### 1. 优点
1.正确发送数据到客户端
使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器
2.更安全
HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数
据在传输过程中不被窃取、改变,确保数据的完整性
3.增加中间人攻击的成本
HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
4.搜索排名更高
谷歌在2014跳转搜索算法,采用HTTPS加密的网站在搜索结果中的排名将会更高
百度也在2018年发布百度对HTTPS站点的扶持态度,表明HTTPS将作为优质特征之一影响搜索排序。
#### 2、缺点
1.页面渲染更耗时间
因为SSL的缘故,HTTPS协议握手阶段比较费时,会使页面的加载时间延长近50%;
2.成本增加
SSL证书需要花钱,功能越强大的证书费用越高;
3.HTTPS连接缓存不如HTTP高效
HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
4.SSL证书通常需要绑定IP
SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
5.有局限性
HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最
关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可
行。
#### 3.https如何进行性能优化?
##### 1.https访问速度优化
1.设置HSTS
服务端返回一个 HSTS 的 http header,浏览器获取到 HSTS 头部之后,在一段时间内,不管用户输入
www.baidu.com还是http://www.baidu.com,都会默认将请求内部跳转成https://www.baidu.com。
2.Session resume
Session Resume 顾名思义就是复用 Session,实现简化握手。
•```
1. 减少了 CPU 消耗,因为不需要进行非对称密钥交换的计算。
2. 提升访问速度,不需要进行完全握手阶段二,节省了一个 RTT 和计算耗时。
•```
3.Nginx设置Ocsp stapling
OSCP Stapling 工作原理简单来说就是浏览器发起 Client Hello 时会携带一个 certificate
status request 的扩展,服务端看到这个扩展后将 OCSP 内容直接返回给浏览器,完成证书状态检查。由
于浏览器不需要直接向 CA 站点查询证书状态,这个功能对访问速度的提升非常明显。
4.使用 SPDY 或者 HTTP2
SPDY 最大的特性就是多路复用,能将多个 HTTP 请求在同一个连接上一起发出去,不像目前的 HTTP 协议
一样,只能串行地逐个发送请求。
HTTP2支持多路复用,有同样的效果。
•```
1. SPDY 和 HTTP2 目前的实现默认使用 HTTPS 协议。
2. SPDY 和 HTTP2 都支持现有的 HTTP 语义和 API,对 WEB 应用几乎是透明的。
•```
5.False start
简单概括 False Start 的原理就是在 client_key_exchange 发出时将应用层数据一起发出来,能够节
省一个 RTT。
##### 2.https计算性能优化
1. 优先使用 ECC椭圆加密算术。
ECC 椭圆加密算术相比普通的离散对数计算速度性能要强很多。
2.使用最新版的 openssl。
一般来讲,新版的 OpenSSL 相比老版的计算速度和安全性都会有提升。
3.硬件加速方案。
- SSL 专用加速卡。
- GPUSSL 加速。
4.TLS 远程代理计算
#### 4.http和https
HTTP:(HyperText Transfer Protocol)超文本传输协议
HTTPS:(Hypertext Transfer Protocol Secure)超文本传输安全协议
HTTP和HTTPS协议的主要区别如下:
HTTPS协议需要CA证书,费用较高;HTTP协议不需要
HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议
使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS的协议端口是443
HTTP协议连接很简单,是无状态的;HTTPS协议是有SSL和HTTP协议构建的可进行加密传输、身份认证的网络
协议,比HTTP更加安全
#### 5.HTTPS为什么是安全的?
HTTPS相对于HTTP协议,加入了TLS/SSL,它的全称为安全传输层协议,是介于TCP和HTTP之间的一层安全
协议。
TLS/SSL的功能实现主要依赖三类基本算法:散列函数hash、对称加密、非对称加密。这三类算法的作用如
下:
基于散列函数验证信息的完整性
对称加密算法采用协商的秘钥对数据加密
非对称加密实现身份认证和秘钥协商
#### 6.HTTPS相对于HTTP的缺陷?
- HTTPS需要做服务器和客户端双方的加密个解密处理,耗费更多服务器资源,过程复杂
- HTTPS协议握手阶段比较费时,增加页面的加载时间
- SSL证书是收费的,功能越强大的证书费用越高
- HTTPS连接服务器端资源占用高很多,支持访客稍多的网站需要投入更大的成本
#### 7.为什么需要证书?
防止中间人攻击,验证服务器身份
#### 8.怎么防止的篡改?
证书是公开的,虽然中间人可以拿到证书,但私钥无法获取,公钥无法推断出私钥,所以篡改后不能用私钥加密,
强行加密客户也无法解密,强行修改内容,会导致证书内容与签名中的指纹不匹配
#### 参考链接
https://blog.csdn.net/qq_42033567/article/details/107902340
https://www.cnblogs.com/Duikerdd/p/12030955.html
3.Nginx设置Ocsp stapling
OSCP Stapling 工作原理简单来说就是浏览器发起 Client Hello 时会携带一个 certificate status request
的扩展,服务端看到这个扩展后将 OCSP 内容直接返回给浏览器,完成证书状态检查。由于浏览器不需
要直接向 CA 站点查询证书状态,这个功能对访问速度的提升非常明显。
4.使用 SPDY 或者 HTTP2
SPDY 最大的特性就是多路复用,能将多个 HTTP 请求在同一个连接上一起发出去,不像目前的 HTTP
协议一样,只能串行地逐个发送请求。
HTTP2支持多路复用,有同样的效果。
1. SPDY 和 HTTP2 目前的实现默认使用 HTTPS 协议。
2. SPDY 和 HTTP2 都支持现有的 HTTP 语义和 API,对 WEB 应用几乎是透明的。
5.False start
简单概括 False Start 的原理就是在 client_key_exchange 发出时将应用层数据一起发出来,能够节省一
个 RTT。
2.https计算性能优化#
1. 优先使用 ECC椭圆加密算术。
ECC 椭圆加密算术相比普通的离散对数计算速度性能要强很多。
2.使用最新版的 openssl。
一般来讲,新版的 OpenSSL 相比老版的计算速度和安全性都会有提升。
3.硬件加速方案。
SSL 专用加速卡。
GPUSSL 加速。
4.TLS 远程代理计算
4.http和https
HTTP:(HyperText Transfer Protocol)超文本传输协议
HTTPS:(Hypertext Transfer Protocol Secure)超文本传输安全协议
HTTP和HTTPS协议的主要区别如下:
HTTPS协议需要CA证书,费用较高;HTTP协议不需要
HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议
使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS的协议端口是443
HTTP协议连接很简单,是无状态的;HTTPS协议是有SSL和HTTP协议构建的可进行加密传输、身份认证
的网络协议,比HTTP更加安全
5.HTTPS为什么是安全的?#
HTTPS相对于HTTP协议,加入了TLS/SSL,它的全称为安全传输层协议,是介于TCP和HTTP之间的一层
安全协议。
TLS/SSL的功能实现主要依赖三类基本算法:散列函数hash、对称加密、非对称加密。这三类算法的作
用如下:
基于散列函数验证信息的完整性
对称加密算法采用协商的秘钥对数据加密
非对称加密实现身份认证和秘钥协商
6.HTTPS相对于HTTP的缺陷?#
HTTPS需要做服务器和客户端双方的加密个解密处理,耗费更多服务器资源,过程复杂
HTTPS协议握手阶段比较费时,增加页面的加载时间
SSL证书是收费的,功能越强大的证书费用越高
HTTPS连接服务器端资源占用高很多,支持访客稍多的网站需要投入更大的成本
7.为什么需要证书?#
防止中间人攻击,验证服务器身份
8.怎么防止的篡改?#
证书是公开的,虽然中间人可以拿到证书,但私钥无法获取,公钥无法推断出私钥,所以篡改后不能用私钥加
密,强行加密客户也无法解密,强行修改内容,会导致证书内容与签名中的指纹不匹配
Git#
1.列举工作中常用的几个git命令?#
新增文件的命令:git add file或者git add .
提交文件的命令:git commit –m或者git commit –a
查看工作区状况:git status –s
拉取合并远程分支的操作:git fetch/git merge或者git pull
查看提交记录命令:git reflog
2. 提交时发生冲突,你能解释冲突是如何产生的吗?你是如何解决的?#
开发过程中,我们都有自己的特性分支,所以冲突发生的并不多,但也碰到过。诸如公共类的公共方
法,我和别人同时修改同一个文件,他提交后我再提交就会报冲突的错误。
发生冲突,在IDE里面一般都是对比本地文件和远程分支的文件,然后把远程分支上文件的内容手工修改
到本地文件,然后再提交冲突的文件使其保证与远程分支的文件一致,这样才会消除冲突,然后再提交
自己修改的部分。特别要注意下,修改本地冲突文件使其与远程仓库的文件保持一致后,需要提交后才
能消除冲突,否则无法继续提交。必要时可与同事交流,消除冲突。
发生冲突,也可以使用命令。
通过git stash命令,把工作区的修改提交到栈区,目的是保存工作区的修改;
通过git pull命令,拉取远程分支上的代码并合并到本地分支,目的是消除冲突;
通过git stash pop命令,把保存在栈区的修改部分合并到最新的工作空间中;
3. 如果本次提交误操作,如何撤销?#
如果想撤销提交到索引区的文件,可以通过git reset HEAD file;如果想撤销提交到本地仓库的文件,可
以通过git reset –soft HEAD^n恢复当前分支的版本库至上一次提交的状态,索引区和工作空间不变更;
可以通过git reset –mixed HEAD^n恢复当前分支的版本库和索引区至上一次提交的状态,工作区不变
更;可以通过git reset –hard HEAD^n恢复当前分支的版本库、索引区和工作空间至上一次提交的状
态。
4. 如果我想修改提交的历史信息,应该用什么命令?#
如果修改最近一次提交的历史记录,就可以用git commit –amend命令;vim编辑的方式;
如果修改之前提交的历史记录,就需要按照下面的步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | 第一步:首先查看前三次的提交历史记录: $ git log - 3 commit a762fcafecbd92bbde088054644e1b0586589c4b (HEAD - > slave) Author: 18073638 < 18073638 @cnsuning.com> Date: Sat Mar 30 10 : 58 : 44 2019 + 0800 four commit commit eedbc93d58780f63dd47f8388f8217892096e89a Author: 18073638 < 18073638 @cnsuning.com> Date: Thu Mar 28 17 : 19 : 52 2019 + 0800 third commit third commit commit 05396135eba85140602107e01e5c211d74f6c739 Author: 18073638 < 18073638 @cnsuning.com> Date: Thu Mar 28 16 : 56 : 19 2019 + 0800 second commit 注意:这里我们想把 053961 的committer对象信息修改为“second commit second commit”. 第二步:执行命令git rebase –i HEAD~ 3 ,会把前 3 次的提交记录按照倒叙列出 来; pick 0539613 second commit pick eedbc93 third commit third commit pick a762fca four commit # Rebase c8d7ad7..a762fca onto c8d7ad7 (3 commands) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit's # . message ( or the oneline, if no original merge commit was # . specified). Use - c <commit> to reword the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out 这里把第一行的‘pick’修改为‘edit’,然后esc + :wq退出vim编辑器; \$ git rebase - i HEAD~ 3 Stopped at 0539613. .. second commit You can amend the commit now, with git commit - - amend Once you are satisfied with your changes, run git rebase - - continue 第三步:根据提示,执行git commit –amend命令,进入vim编辑器并修改提交信息。 $ git commit - - amend [detached HEAD 20fe643 ] second commit second commit Date: Thu Mar 28 16 : 56 : 19 2019 + 0800 1 file changed, 1 insertion( + ) 第四步:然后执行git rebase – continue 命令 $ git rebase - - continue Successfully rebased and updated refs / heads / slave. 查看修改结果 $ git log - 3 commit 9024049ef990e79fa61295d5c2b64d70017cf412 (HEAD - > slave) Author: 18073638 < 18073638 @cnsuning.com> Date: Sat Mar 30 10 : 58 : 44 2019 + 0800 four commit commit 79cb4e26dd300591e6352d0488802f43b65c8ba2 Author: 18073638 < 18073638 @cnsuning.com> Date: Thu Mar 28 17 : 19 : 52 2019 + 0800 third commit third commit commit 20fe643cbf80cdcc649d732065e8ebf4caf773c7 Author: 18073638 < 18073638 @cnsuning.com> Date: Thu Mar 28 16 : 56 : 19 2019 + 0800 second commit second commit / / 修改成功。 |
5. 你使用过git stash命令吗?你一般什么情况下会使用它?#
命令git stash是把工作区修改的内容存储在栈区。
以下几种情况会使用到它:
解决冲突文件时,会先执行git stash,然后解决冲突;
遇到紧急开发任务但目前任务不能提交时,会先执行git stash,然后进行紧急任务的开发,然后通
过git stash pop取出栈区的内容继续开发;
切换分支时,当前工作空间内容不能提交时,会先执行git stash再进行分支切换;
6. 如何查看分支提交的历史记录?查看某个文件的历史记录呢?#
查看分支的提交历史记录:
命令git log –number:表示查看当前分支前number个详细的提交历史记录;
命令git log –number –pretty=oneline:在上个命令的基础上进行简化,只显示sha-1码和提交信
息;
命令git reflog –number: 表示查看所有分支前number个简化的提交历史记录;
命令git reflog –number –pretty=oneline:显示简化的信息历史信息;
如果要查看某文件的提交历史记录,直接在上面命令后面加上文件名即可。
注意:如果没有number则显示全部提交次数。
7. 能不能说一下git fetch和git pull命令之间的区别?#
简单来说:git fetch branch是把名为branch的远程分支拉取到本地;而git pull branch是在fetch的基础
上,把branch分支与当前分支进行merge;因此pull = fetch + merge。
8. 使用过git merge和git rebase吗?它们之间有什么区别?#
简单的说,git merge和git rebase都是合并分支的命令。
git merge branch会把branch分支的差异内容pull到本地,然后与本地分支的内容一并形成一个
committer对象提交到主分支上,合并后的分支与主分支一致;
git rebase branch会把branch分支优先合并到主分支,然后把本地分支的commit放到主分支后面,合
并后的分支就好像从合并后主分支又拉了一个分支一样,本地分支本身不会保留提交历史。
9. 能说一下git系统中HEAD、工作树和索引之间的区别吗?#
HEAD文件包含当前分支的引用(指针);
工作树是把当前分支检出到工作空间后形成的目录树,一般的开发工作都会基于工作树进行;
索引index文件是对工作树进行代码修改后,通过add命令更新索引文件;GIT系统通过索引index文件生
成tree对象;
10. 之前项目中是使用的GitFlow工作流程吗?它有什么好处?#
GitFlow可以用来管理分支。GitFlow工作流中常用的分支有下面几类:
master分支:最为稳定功能比较完整的随时可发布的代码,即代码开发完成,经过测试,没有明显
的bug,才能合并到 master 中。请注意永远不要在 master 分支上直接开发和提交代码,以确保
master 上的代码一直可用;
develop分支;用作平时开发的主分支,并一直存在,永远是功能最新最全的分支,包含所有要发
布 到下一个 release 的代码,主要用于合并其他分支,比如 feature 分支; 如果修改代码,新建
feature 分支修改完再合并到 develop 分支。所有的 feature、release 分支都是从 develop 分支
上拉的。
feature分支;这个分支主要是用来开发新的功能,一旦开发完成,通过测试没问题(这个测试,
测试新功能没问题),我们合并回develop 分支进入下一个 release
release分支;用于发布准备的专门分支。当开发进行到一定程度,或者说快到了既定的发布日,
可以发布时,建立一个 release 分支并指定版本号(可以在 finish 的时候添加)。开发人员可以对
release 分支上的代码进行集中测试和修改bug。(这个测试,测试新功能与已有的功能是否有冲
突,兼容性)全部完成经过测试没有问题后,将 release 分支上的代码合并到 master 分支和
develop 分支
hotfix分支;用于修复线上代码的bug。从 master 分支上拉。完成 hotfix 后,打上 tag 我们合并
回 master 和 develop 分支。
GitFlow主要工作流程
1.初始化项目为gitflow , 默认创建master分支 , 然后从master拉取第一个develop分支
2.从develop拉取feature分支进行编码开发(多个开发人员拉取多个feature同时进行并行开发 , 互
不影响)
3.feature分支完成后 , 合并到develop(不推送 , feature功能完成还未提测 , 推送后会影响其他功能
分支的开发);合并feature到develop , 可以选择删除当前feature , 也可以不删除。但当前feature
就不可更改了,必须从release分支继续编码修改
4.从develop拉取release分支进行提测 , 提测过程中在release分支上修改BUG
5.release分支上线后 , 合并release分支到develop/master并推送;合并之后,可选删除当前release分
支,若不删除,则当前release不可修改。线上有问题也必须从master拉取hotfix分支进行修改;
6.上线之后若发现线上BUG , 从master拉取hotfix进行BUG修改;
7.hotfix通过测试上线后,合并hotfix分支到develop/master并推送;合并之后,可选删除当前hotfix ,
若不删除,则当前hotfix不可修改,若补丁未修复,需要从master拉取新的hotfix继续修改;
8.当进行一个feature时 , 若develop分支有变动 , 如其他开发人员完成功能并上线 , 则需要将完成的功能
合并到自己分支上,即合并develop到当前feature分支;
9.当进行一个release分支时 , 若develop分支有变动 , 如其他开发人员完成功能并上线 , 则需要将完成的
功能合并到自己分支上,即合并develop到当前release分支 (!!! 因为当前release分支通过测试后会发布
到线上 , 如果不合并最新的develop分支 , 就会发生丢代码的情况);
GitFlow的好处
为不同的分支分配一个明确的角色,并定义分支之间如何交互以及什么时间交互;可以帮助大型项目理
清分支之间的关系,简化分支的复杂度。
11. 使用过git cherry-pick,有什么作用?#
命令git cherry-pick可以把branch A的commit复制到branch B上。
在branch B上进行命令操作:
复制单个提交:git cherry-pick commitId
复制多个提交:git cherry-pick commitId1…commitId3
注意:复制多个提交的命令不包含commitId1.
12. git跟其他版本控制器有啥区别?#
GIT是分布式版本控制系统,其他类似于SVN是集中式版本控制系统。
分布式区别于集中式在于:每个节点的地位都是平等,拥有自己的版本库,在没有网络的情况下,对工
作空间内代码的修改可以提交到本地仓库,此时的本地仓库相当于集中式的远程仓库,可以基于本地仓
库进行提交、撤销等常规操作,从而方便日常开发。
13.我们在本地工程常会修改一些配置文件,这些文件不需要被提交,而我们又不想#
每次执行git status时都让这些文件显示出来,我们该如何操作?
首先利用命令touch .gitignore新建文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ touch .gitignore 然后往文件中添加需要忽略哪些文件夹下的什么类型的文件 $ vim .gitignore $ cat .gitignore / target / class .settings .imp * .ini |
注意:忽略/target/class文件夹下所有后缀名为.settings,.imp的文件,忽略所有后缀名为.ini的文件。
14. 如何把本地仓库的内容推向一个空的远程仓库?#
首先确保本地仓库与远程之间是连同的。如果提交失败,则需要进行下面的命令进行连通:
git remote add origin XXXX
意:XXXX是你的远程仓库地址。
如果是第一次推送,则进行下面命令:
1 | git push - u origin master |
注意:-u 是指定origin为默认主分支
之后的提交,只需要下面的命令:
1 | git push origin master |
15.如在 Git 恢复先前的提交?#
假设你的情形是这样,其中 C 是你的 HEAD,(F) 是你文件的状态。
(F)
A-B-C
master
要修改提交中的更改:
1 | git reset - - hard HEAD~ 1 |
现在 B 是 HEAD,因为你使用了 --hard,所以你的文件将重置到提交 B 时的状态。 要撤销提交但保
留更改:
1 | git reset HEAD~ 1 |
现在我们告诉 Git 将 HEAD 指针移回(后移)一个提交(B),并保留文件原样,然后你可以 git status
来显示你已经检入 C 的更改。 撤销提交但保留文件和索引:
git reset --soft HEAD~1
执行此操作后,git status,你讲看到索引中的文件跟以前一致
16.什么是“git cherry-pick”?#
命令 git cherry-pick 通常用于把特定提交从存储仓库的一个分支引入到其他分支中。常见的用途是从
维护的分支到开发分支进行向前或回滚提交。
这与其他操作(例如:合并(merge)、变基(rebase))形成鲜明对比,后者通常是把许多提交应用到其
他分支中。小结:
git cherry-pick
参考链接
https://blog.csdn.net/nobody_1/article/details/88956315
https://www.pianshen.com/article/576320826/
webpack#
1.webpack与grunt、gulp的不同?#
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻
量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一
系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流
程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的
Loader来处理不同的文件,用Plugin来扩展webpack功能。
所以总结一下:
从构建思路来说
1.gulp和grunt需要开发者将整个前端构建过程拆分成多个 Task ,并合理控制所有 Task 的调用关
系
2.webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工
对于知识背景来说
gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
2.与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用#
webpack?
同样是基于入口的打包工具还有以下几个主流的:
webpack
rollup
parcel
从应用场景上来看:
webpack适用于大型复杂的前端站点构建
rollup适用于基础库的打包,如vue、react
parcel适用于简单的实验性项目,他可以满足低门槛的快速看到效果
由于parcel在打包过程中给出的调试信息十分有限,所以一旦打包出错难以调试,所以不建议复杂的项目使用
parcel
3.有哪些常见的Loader?他们是解决什么问题的?#
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到
代码中去
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码
4.有哪些常见的Plugin?他们是解决什么问题的?#
define-plugin:定义环境变量
commons-chunk-plugin:提取公共代码
uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码
5.Loader和Plugin的不同?#
不同的作用
Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如
果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解
析非JavaScript文件的能力。
Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在
Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过
Webpack 提供的 API 改变输出结果。
不同的用法
Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都
是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数
(options)
Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传
入。
6.webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全#
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
1.初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
2.开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法
开始执行编译;
3.确定入口:根据配置中的 entry 找出所有的入口文件;
4.编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,
再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
5.完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以
及它们之间的依赖关系;
6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk
转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特
定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
7.是否写过Loader和Plugin?描述一下编写loader或plugin的思路?#
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,并且每个Loader通过链式操作,将源
文件一步步翻译成想要的样子。
编写Loader时要遵循单一原则,每个Loader只做一种"转义"工作。 每个Loader的拿到的是源文件内容
(source),可以通过返回值的方式将处理后的内容输出,也可以调用this.callback()方法,将内容返回
给webpack。 还可以通过 this.async()生成一个callback函数,再用这个callback将处理后的内容输出出
去。 此外webpack还为开发者准备了开发loader的工具函数集——loader-utils。
相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,
Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
8.webpack的热更新是如何做到的?说明其原理?#
webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。 这个机制可以做到不用刷
新浏览器而将新变更的模块替换掉旧的模块。
原理:
图片来自饿了么前端@知乎专栏
首先要知道server端和client端都做了处理工作
1.第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生修改,webpack 监听到文件变
化,根据配置文件对模块重新编译打包,并将打包后的代码通过简单的 JavaScript 对象保存在内存中。
2.第二步是 webpack-dev-server 和 webpack 之间的接口交互,而在这一步,主要是 dev-server 的中
间件 webpack-dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack
暴露的 API对代码变化进行监控,并且告诉 webpack,将代码打包到内存中。
3.第三步是 webpack-dev-server 对文件变化的一个监控,这一步不同于第一步,并不是监控代码变化
重新打包。当我们在配置文件中配置了devServer.watchContentBase 为 true 的时候,Server 会监听
这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload。注意,这儿是浏览
器刷新,和 HMR 是两个概念。
4.第四步也是 webpack-dev-server 代码的工作,该步骤主要是通过 sockjs(webpack-dev-server 的依
赖)在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的各个阶段的状态信
息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据这些 socket 消
息进行不同的操作。当然服务端传递的最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值
来进行模块热替换。
5.webpack-dev-server/client 端并不能够请求更新的代码,也不会执行热更模块操作,而把这些工作又
交回给了 webpack,webpack/hot/dev-server 的工作就是根据 webpack-dev-server/client 传给它的
信息以及 dev-server 的配置决定是刷新浏览器呢还是进行模块热更新。当然如果仅仅是刷新浏览器,也
就没有后面那些步骤了。
6.HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的
hash 值,它通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个 json,该
json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请求,获取到最
新的模块代码。这就是上图中 7、8、9 步骤。
7.而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进行
对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间
的依赖引用。
8.最后一步,当 HMR 失败后,回退到 live reload 操作,也就是进行浏览器刷新来获取最新打包代码。
9.如何利用webpack来优化前端性能?(提高性能和体验)#
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的
UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压
缩css
利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用
webpack对于output参数和各loader的publicPath参数来修改资源路径
删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时
追加参数--optimize-minimize来实现
提取公共代码。
10.如何提高webpack的构建速度?#
1.多入口情况下,使用CommonsChunkPlugin来提取公共代码
2.通过externals配置来提取常用库
3.利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修
改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
4.使用Happypack 实现多线程加速编译
5.使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了
多核并行压缩来提升压缩速度
6.使用Tree-shaking和Scope Hoisting来剔除多余代码
11.怎么配置单页应用?怎么配置多页应用?#
单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可,这里不再赘述
多页应用的话,可以使用webpack的 AutoWebPlugin来完成简单自动化的构建,但是前提是项目的目录
结构必须遵守他预设的规范。 多页应用中要注意的是:
每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了
同一套css样式表
随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加
新页面还需要修改构建配置
12.npm打包时需要注意哪些?如何利用webpack来更好的构建?#
Npm是目前最大的 JavaScript 模块仓库,里面有来自全世界开发者上传的可复用模块。你可能只是JS模
块的使用者,但是有些情况你也会去选择上传自己开发的模块。 关于NPM模块上传的方法可以去官网上
进行学习,这里只讲解如何利用webpack来构建。
NPM模块需要注意以下问题:
1.要支持CommonJS模块化规范,所以要求打包后的最后结果也遵守该规则。
2.Npm模块使用者的环境是不确定的,很有可能并不支持ES6,所以打包的最后结果应该是采用ES5编写
的。并且如果ES5是经过转换的,请最好连同SourceMap一同上传。
3.Npm包大小应该是尽量小(有些仓库会限制包大小)
4.发布的模块不能将依赖的模块也一同打包,应该让用户选择性的去自行安装。这样可以避免模块应用
者再次打包时出现底层模块被重复打包的情况。
5.UI组件类的模块应该将依赖的其它资源文件,例如.css文件也需要包含在发布的模块里。
基于以上需要注意的问题,我们可以对于webpack配置做以下扩展和优化:
1.CommonJS模块化规范的解决方案: 设置output.libraryTarget='commonjs2'使输出的代码符合
CommonJS2 模块化规范,以供给其它模块导入使用
2.输出ES5代码的解决方案:使用babel-loader把 ES6 代码转换成 ES5 的代码。再通过开启devtool:
'source-map'输出SourceMap以发布调试。
3.Npm包大小尽量小的解决方案:Babel 在把 ES6 代码转换成 ES5 代码时会注入一些辅助函数,最终导
致每个输出的文件中都包含这段辅助函数的代码,造成了代码的冗余。解决方法是修改.babelrc文件,
为其加入transform-runtime插件
4.不能将依赖模块打包到NPM模块中的解决方案:使用externals配置项来告诉webpack哪些模块不需要
打包。
5.对于依赖的资源文件打包的解决方案:通过css-loader和extract-text-webpack-plugin来实现,配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | const ExtractTextPlugin = require( 'extract-text-webpack-plugin' ); module.exports = { module: { rules: [ { // 增加对 CSS 文件的支持 test: /\.css/, // 提取出 Chunk 中的 CSS 代码到单独的文件中 use: ExtractTextPlugin.extract({ use: [ 'css-loader' ] }), }, ] }, plugins: [ new ExtractTextPlugin({ // 输出的 CSS 文件名称 filename: 'index.css' , }), ], }; |
13.如何在vue项目中实现按需加载?#
Vue UI组件库的按需加载 为了快速开发前端项目,经常会引入现成的UI组件库如ElementUI、iView等,
但是他们的体积和他们所提供的功能一样,是很庞大的。 而通常情况下,我们仅仅需要少量的几个组件
就足够了,但是我们却将庞大的组件库打包到我们的源码中,造成了不必要的开销。
不过很多组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component和AntDesign
出品的babel-plugin-import 安装以上插件后,在.babelrc配置中或babel-loader的参数中进行设置,即
可实现组件按需加载了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | { "presets" : [[ "es2015" , { "modules" : false }]], "plugins" : [ [ "component" , { "libraryName" : "element-ui" , "styleLibraryName" : "theme-chalk" } ] ] } |
单页应用的按需加载 现在很多前端项目都是通过单页应用的方式开发的,但是随着业务的不断扩展,会
面临一个严峻的问题——首次加载的代码量会越来越多,影响用户的体验。
通过import()语句来控制加载时机,webpack内置了对于import()的解析,会将import()中引入的模块作
为一个新的入口在生成一个chunk。 当代码执行到import()语句时,会去加载Chunk对应生成的文件。
import()会返回一个Promise对象,所以为了让浏览器支持,需要事先注入Promise polyfill
14.webpack是解决什么问题而生的?#
require everything, bundle everything.
15.如何配置多入口文件?#
https://juejin.im/post/5a534cb9f265da3e4674ebeb
16.webpack中的模块解析规则#
Loader像一个"翻译官"把读到的源文件内容转义成新的文件内容,并且每个Loader通过链式操作,将源
文件一步步翻译成想要的样子。
编写Loader时要遵循单一原则,每个Loader只做一种"转义"工作。 每个Loader的拿到的是源文件内容
( source ),可以通过返回值的方式将处理后的内容输出,也可以调用 this.callback() 方法,将内
容返回给webpack。 还可以通过 this.async() 生成一个 callback 函数,再用这个callback将处理后
的内容输出出去。 此外 webpack 还为开发者准备了开发loader的工具函数集—— loader-utils 。
相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,
Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
17.webpack中的模块解析规则具体实现#
使用 enhanced-resolve,webpack 能解析三种文件路径:
绝对路径
import '/home/me/file';
import 'C:\\Users\\me\\file';
由于已经获得文件的绝对路径,因此不需要再做进一步解析。
相对路径
import '../src/file1';
import './file2';
在这种情况下,使用 import 或 require 的资源文件所处的目录,被认为是上下文目录。在
import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径。
模块路径(重点)
import 'module';
import 'module/lib/file';
在 resolve.modules 中指定的所有目录检索模块。 你可以通过配置别名的方式来替换初始模块路径,
resolve.alias 配置选项。
如果 package 中包含 package.json 文件,那么在 resolve.exportsFields 配置选项中指定的字
段会被依次查找, package.json 中的第一个字段会根据 package 导出指南确定 package 中可用的
export 。 一旦根据上述规则解析路径后,resolver 将会检查路径是指向文件还是文件夹。
1. 指向文件:
如果文件具有扩展名,则直接将文件打包。
否则,将使用 resolve.extensions 选项作为文件扩展名来解析,此选项会告诉解析器在解
析中能够接受那些扩展名(例如 .js,.jsx)。
2. 指向一个文件夹,则进行如下步骤寻找具有正确扩展名的文件:
如果文件夹中包含 package.json 文件,则会根据 resolve.mainFields 配置中的字段顺
序查找,并根据 package.json 中的符合配置要求的第一个字段来确定文件路径。
如果不存在 package.json 文件或 resolve.mainFields 没有返回有效路径,则会根据
resolve.mainFiles 配置选项中指定的文件名顺序查找,看是否能在 import/require 的
目录下匹配到一个存在的文件名。
然后使用 resolve.extensions 选项,以类似的方式解析文件扩展名。
18.什么是模块热替换#
模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,
而无需重新加载整个页面。
主要是通过以下几种方式,来显著加快开发速度:
保留在完全重新加载页面期间丢失的应用程序状态。
只更新变更内容,以节省宝贵的开发时间。
在源代码中 CSS/JS 产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直
接更改样式。
参考链接
https://zhuanlan.zhihu.com/p/44438844
https://juejin.cn/post/6922351695833858062
计算机基础#
1.CPU基础#
CPU即处理器,是计算机中控制数据操控的电路。它主要由三部分构成:算术/逻辑单元、控制单元和寄
存器单元。它们的作用分别为执行运算、协调机器活动以及临时存储。
2.CPU与主存#
CPU中的寄存器分为通用寄存器和专用寄存器,通用寄存器用于临时存放CPU正在使用的数据,而专用
寄存器用于CPU专有用途,比如指令寄存器和程序计数器。CPU与主存的通过总线进行通信,CPU通过
控制单元能够操作主存中的数据。
执行两个数值相加的过程大致为:从主存读取第一个值放到寄存器1->从主存读取第二个值放到寄存器2>两个寄存器保存的值作为输入送到加法电路->将加法结果保存到寄存器3->控制单元将结果放到主存
中。
3.程序等同数据#
原始的计算机并不像现代计算机一样将程序保存起来,以前的人们只对数据进行保存,而设备执行的步
骤作为计算机的一部分而被内置在控制单元中。这样就很不灵活,最多只能通过重新布线来提升灵活
性。将程序与数据视作相同本质是很大的思想突破,因为人们一直认为它们是不同的事物,数据应该存
放在主存中而程序应该属于CPU的一部分。
将程序作为数据一样保存在主存中大有好处,控制单元能够从主存读取程序,然后对它们解码并执行。
当我们要修改执行程序时可以在计算机的主存中修改,而不必对CPU更改或重新布线。
4.指令系统#
程序包含了大量的机器指令,CPU对这些指令进行解码并执行。CPU分为两类体系:精简指令集计算机
(RISC)和复杂指令集计算机(CISC)。RISC提供了最小的机器指令集,计算机效率高速度快且制造成本
低。而CISC提供了强大丰富的指令集,能更方便实现复杂的软件。
机器指令分为三类:数据传输类、算术/逻辑类与控制类。
数据传输类指令用于将数据从一个地方移动到另一个地方。比如将主存单元的内容加载到寄存器的
LOAD指令,反之将寄存器的内容保存到主存的STORE指令。此外,CPU与其它设备(键盘、鼠标、打
印机、显示器、磁盘等)进行通信的指令被称为I/O指令。
算术/逻辑类指令用于让控制单元请求在算术/逻辑单元内执行运算。这些运算包括算术、与、或、异或
和位移等。
控制类指令用于指导程序执行。比如转移(JUMP)指令,它包括无条件转移和条件转移。
5.指令寄存器与程序计数器#
CPU将主存的指令加载进来解码并执行,其中涉及两个重要寄存器:指令寄存器与程序计数器。指令寄
存器用于存储正在执行的指令,而程序计数器则保持下一个待执行的指令地址。
CPU向主存请求加载程序计数器指定的地址的指令,将其存放到指令寄存器中,加载后将程序计数器的
值加2(假如指令长度为2个字节)。
6.指令如何执行#
比如我们要计算11+22,假设过程为:将主存地址为00的内容加载到寄存器1中->将主存地址为01的内容
加载到寄存器2中->将寄存器1和寄存器2的数据相加并将结果保存到寄存器3->将寄存器3的结果存储到
主存地址为02的位置->停止。
这个过程CPU涉及到四个操作:加载(load)、存储(store)、加法(add)和停止(halt)。可以对这些操作进行
编码,比如可以分别用1、2、3、0000表示。
1100
1201
3312
2302
0000
7.控制器#
CPU与其他设备的通信一般通过控制器来实现,控制器可能在主板上,也可能以电路板形式插到主板。
控制器本身可以看成是小型计算机,也有自己简单的CPU。以前每连接一种外设都需要购买对应的控制
器,而现在随着通用串行总线(USB)成为通用的标准,很多外设都可以直接用USB控制器作为通信接
口。每个控制器都连接在总线上,通过总线进行通信。
8.直接存储器存取#
直接存储器存取(DMA)是一种提升外设通信性能的措施,CPU并非总是需要使用总线,在总线空闲的
时间里控制器能够充分利用起来。因为控制器都与总线相连接,而控制器又有执行指令的能力,所以可
以将CPU的一些工作分给控制器来完成。比如在磁盘中检索数据时,CPU可以将告知控制器,然后由控
制器找到数据并放到主存上,期间CPU可以去执行其他任务。这样能节省CPU资源。不过DMA会使总线
通信更加复杂,而且会导致总线竞争问题。总线瓶颈源自冯诺依曼体系结构。
专注于人工智能、读书与感想、聊聊数学、计算机科学、分布式、机器学习、深度学习、自然语言处
理、算法与数据结构、Java深度、Tomcat内核等。
9.什么是程序局部性?为什么会有程序的空间局部性?#
程序局部性是指程序在运行时呈现出局部性规律,在一段时间间隔内,程序的执行是局限在某个部份,所访
问的存储空间也只局限在某个区域。
程序的空间局部性是指若一个存储单元被访问,那么它附近的单元也可能被访问,这是由于程序的顺序执行
引起的。
10.为了实现重定位,需要哪些硬件?#
最简单的方式是在系统中增设一个重定位寄存器,用来存放正在执行作业的内存地址,每次访问数据时,由
硬件自动将相对地址与重定位寄存器中的起始地址相加,形成实际的特理地址。当然在分页式与分段式系
统中,具地址变换机构,以及快表等硬件。
11.在交互式系统中,非剥夺是不是一个好的策略?为什么?#
非剥夺方式:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生某事件而阻
塞时,才把处理机分配给另一个进程。
剥夺方式:当一个进程正在运行时,系统可以基于某种原则,剥夺已分配给它的处理机,将之分配给其它进
程。剥夺原则有:优先权原则、短进程、优先原则、时间片原则。
在分时系统中不剥夺并不是一个好的策略。因为,在分时系统中,除了交互性以外,及时性是很重要的性能
因素。当一个作业被阻塞后,CPU就完全空闲了,别的用户的及时性就无法保证了,而完全可以把这些时间
分配给别的作业运行。以提高整体的吞吐量。
12.谈一谈计算机网络和分布式计算机系统的区别#
两者在计算机硬件连接、系统拓朴结构和通信控制等方面基本都是一样的,它们都具有通信和资源共享的
功能。
区别关键在于:分布式计算机系统是在分布式计算机操作系统支持下,进行分布式数据库处理的,也就是说
各互联的计算机可以互相协调工作,共同完成一项任务,多台计算机上并行运行。且具有透明性,用户不知
道数据、资源的具体位置,整个网络中所有计算机就像是一台计算机一样;而计算机网络却不具备这种功
能,计算机网络系统中的各计算机通常是各自独立进行工作的。
13.为什么要引入多道程序技术?#
因为引入多道程序技术后,可以进一步提高了CPU利用率(阻塞),提高内存和I/O设备利用率(小作业把内存
浪费了),增加系统吞吐量(两都提高后的必然)。
14.处理器如何读并解释存储在内存中的指令#
比如在Unix系统中,通过shell输入./hello,“hello world”是如何展示到屏幕上的呢
linux> ./hello
hello world
linux>
要想了解其中原理,需要先知道计算机的硬件组成
15.总线#
贯穿整个系统的电子通道,传输的是定长的字节块。而字节中的字长是一个系统参数,各系统不相同,
现在通常是4字节(32位),8字节(64位)
16.I/O设备#
I/O(输入/输出)设备是系统与外部世界的联系通道。键盘、鼠标、显示器、磁盘都输入I/O设备,并通
过控制器或者适配器与I/O总线相连
17.主存#
主存是一个临时存储设备,在处理器处理程序过程中,临时存储程序和数据,从物理上讲,是由一组动
态随机存取存储器(DRAM)芯片组成的,从逻辑上讲,存储的是一个线性的字节数组,每个字节都有
唯一的地址(数组索引)。
18.处理器#
中央处理单元(CPU),简称处理器,是解释或执行存储在主存中指令的引擎。
19.计算机如何访问信息#
CPU通过寄存器来存储整数数据和指针,比如X86-64的CPU包含一组16个存储64位的通用目的寄存器,
这16个寄存器各司其职,其中最特别的是栈指针%rsp,用来指明运行时栈的结束位置。更重要的是,有
一组标准的编程规范控制着如何使用寄存器来管理栈、传递函数参数、函数的返回值、以及存储局部或
临时变量。
20.什么是操作数指示符#
大多数指令中有一个或多个“操作数”,指示出执行一个操作中的源数据以及放置结果的目标位置。操作
数有三类
立即数,用来表示常数值
寄存器,用来表示某个寄存器的内容
内存引用,根据计算出来的地址访问某个内容
21.如何传送数据#
通过指令,可以实现寄存器和内存之间的数据传送
C语言中的“指针”指的是地址,间接引用指针就是将该指针放到一个寄存器中,然后在内存引用中
使用这个寄存器
22.栈数据如何压入和弹出#
因为栈和数据都是放到同一内存中的,可以通过内存寻址方法来访问栈内的任意位置,栈向地址方向增
长,所以压栈是减少栈指针(寄存器%rsp的值),并将数据存放到内存中,而出栈是从内存中读数据,
增加栈指针的值
23.如何进行算数和逻辑操作#
也是通过指令,大多数操作分成了指令类,指令类有各种带不同大小操作数的变种,比如指令类ADD由
四个加法指令组成:addb、addw、addl和addq,分别是字节加法、字加法、双字加法和四字加法。每
个指令类都对应四个操作,分别是
加载有效地址
一元操作
二元操作
移位
其中一元操作有一个操作数、二元操作有两个操作数
24.什么是“加载有效地址”#
加载有效地址指令leaq实际上是movq指令的变形,它的指令形式是从内存读数据到寄存器,但该指令
并不是从内存位置读入数据,而是将有效地址写入目的操作数。
25.什么是一元和二元操作#
1. 一元操作只有一个操作数,即是源又是目的,可以是一个寄存器,也可以是一个内存位置,比如
i++和i-2. 二元操作,第二个数即是源又是目的,比如x-=y,第一个数是源操作数,第二个数是目的操作数
参考链接
https://blog.csdn.net/lingess/article/details/98479704
https://juejin.cn/post/6844904181816360968
跨域#
1.什么是跨域#
协议、端口和域名不一致导致的跨域 跨域是因为浏览器需要遵守同源策略,发出的请求即使响应成功,
也被浏览器拦截下来
2.同源策略#
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互、这是一个用于隔离
潜在恶意文件的重要安全机制、
3.为什么有同源策略#
如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。
1、 防御 XSS 攻击#
XSS,即 Cross Site Script,中译是跨站脚本攻击。
HttpOnly 防止劫取 Cookie
用户的输入检查
服务端的输出检查
2、防御 CSRF 攻击#
CSRF,即 Cross Site Request Forgery,中译是跨站请求伪造,是一种劫持受信任用户向服务器发送非
预期请求的攻击方式。
验证码
Referer Check
Token验证
4.跨域的解决方案#
1、通过jsonp跨域
2、document.domain + iframe跨域
3、location.hash + iframe
4、window.name + iframe跨域
5、postMessage跨域
6、跨域资源共享(CORS)
7、nginx代理跨域
8、nodejs中间代理跨域
9、WebSocket协议跨域
5.jsonp原理#
jsonp的核心则是动态添加 script 标签调用服务器提供的js脚本,允许用户传递一个callback参数给服务
器,然后服务器返回数据时会将这个callback参数作为函数名老包裹JSON数据,这样客户端就可以随意
定制自己的函数来自动处理返回数据了
JSONP 使用简单且兼容性不错,但是只限于 get 请求。(缺点)
通用的办法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <script> var script = document.createElement( 'script' ); script.type = 'text/javascript' ; // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数 script.src = 'http://www.domain2.com:8080/login? user=admin&callback=handleCallback' ; document.head.appendChild(script); // 回调执行函数 function handleCallback(value) { console.log(value) } </script> |
vue.js实现
1 2 3 4 5 6 7 8 9 10 11 12 13 | this .$http.jsonp( 'http://www.domain2.com:8080/login' , { params: {}, jsonp: 'handleCallback' }).then((res) => { console.log(res); }) 123456 |
后端node.js代码实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | var querystring = require( 'querystring' ); var http = require( 'http' ); var server = http.createServer(); server.on( 'request' , function (req, res) { var params = qs.parse(req.url.split( '?' )[1]); var fn = params.callback; // jsonp返回设置 res.writeHead(200, { 'Content-Type' : 'text/javascript' }); res.write(fn + '(' + JSON.stringify(params) + ')' ); res.end(); }); server.listen( '8080' ); console.log( 'Server is running at port 8080...' ); |
6.常见的跨域场景#
摘自https://segmentfault.com/a/1190000011145364
说明
URL
是否允许通信
http://www.domain.com/a.js
http://www.domain.com/b.js
同一域名,不同文件或路径
允许
同一域名,不同端口
不允许
同一域名,不同协议
不允许
域名和域名对应相同ip
不允许
主域相同,子域不同
不允许
http://www.domain.com/lab/c.js
http://www.domain.com:8000/a.js
http://www.domain.com/b.js
http://www.domain.com/a.js
https://www.domain.com/b.js
http://www.domain.com/a.js
http://192.168.4.12/b.js
http://www.domain.com/a.js
http://x.domain.com/b.js
http://domain.com/c.js
http://www.domain1.com/a.js
http://www.domain2.com/b.js
不同域名
不允许
7.postMessage跨域#
这是由H5提出来的的API,IE8以上支持这个功能。
window.postMessage() 方法可以安全地实现跨源通信。
window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后,向目标窗口派发一个
MessageEvent 消息。
用法: postMessage(data,origin) 方法接受两个参数
data : html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用
JSON.stringify()序列化。
origin : 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同
源的话设置为"/"。
例子:
1.)a.html: (http://www.domain1.com/a.html)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | < iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"> </ iframe > < script > var iframe = document.getElementById('iframe'); iframe.onload = function() { var data = { name: 'aym' }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // 向domain2传送跨域数据 iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com'); }; // 接受domain2返回数据 window.addEventListener('message', function(e) { alert('data from domain2 ---> ' + e.data); }, false); </ script > 12345678910111213141516 2.)b.html: (http://www.domain2.com/b.html) < script > // 接收domain1的数据 window.addEventListener('message', function(e) { alert('data from domain1 ---> ' + e.data); var data = JSON.parse(e.data); if (data) { data.number = 16; // 处理后再发回domain1 window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com'); } }, false); </ script > |
8.资源共享跨域(CORS)#
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:
前后端都需要设置。
目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也
已经成为主流的跨域解决方案。
但不能实现修改cookie中domain信息,不方便当前域cookie写入,即不能实现登录认证。
9.nginx代理跨域#
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访
问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
nginx具体配置:
#proxy服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | server { listen 81 server_name www.domain1.com; location / { proxy_pass http: / / www.domain2.com: 8080 ; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源 限制,下面的跨域配置可不启用 add_header Access - Control - Allow - Origin http: / / www.domain1.com; #当前端只 跨域不带cookie时,可为 * add_header Access - Control - Allow - Credentials true; } } |
10.nodejs中间件代理跨域#
node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也
可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便
接口登录认证。
1、 非vue框架的跨域(2次跨域)#
利用node + express + http-proxy-middleware搭建一个proxy服务器。
中间件服务器:
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/', proxy({
// 代理跨域目标接口
target: 'http://www.domain2.com:8080',
changeOrigin: true,
// 修改响应头信息,实现跨域并允许带cookie
onProxyRes: function(proxyRes, req, res) {
res.header('Access-Control-Allow-Origin', 'http://www.domain1.com');
res.header('Access-Control-Allow-Credentials', 'true');
},
// 修改响应信息中的cookie域名
cookieDomainRewrite: 'www.domain1.com'
// 可以为false,表示不修改
}));
app.listen(3000);
console.log('Proxy server is listen at port 3000...');
123456789101112131415161718192021
2、 vue框架跨域#
利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口
代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域
信息了。
webpack.config.js部分配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | module.exports = { entry: {}, module: {}, ... devServer: { historyApiFallback: true, proxy: [{ context: '/sbcweb' , target: 'http://www.domian2.com:8080' , changeOrigin: true, / / 代理跨域目标接口 secure: false, / / 当代理某些https服务报错时用 cookieDomainRewrite: 'www.domain1.com' / / 可以为false,表示不修改 / / 填写域名表示可以更改cookie的域名值为此域名,便可以导入cookie到网站中。 }], noInfo: true } } |
11.webscoket协议跨域#
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通
讯,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了
更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
WebSocket不会专门用来做跨域,而是作为消息推送或者聊天等.
参考链接
https://blog.csdn.net/qq_42367749/article/details/105001503
https://www.jianshu.com/p/a318480c2b5f
数据结构与算法#
1. 什么是复杂度分析 ?#
1.数据结构和算法解决是 “如何让计算机更快时间、更省空间的解决问题”。
2.因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能。
3.分别用时间复杂度和空间复杂度两个概念来描述性能问题,二者统称为复杂度。
4.复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。
2. 为什么要进行复杂度分析 ?#
1.和性能测试相比,复杂度分析有不依赖执行环境、成本低、效率高、易操作、指导性强的特点。
2.掌握复杂度分析,将能编写出性能更优的代码,有利于降低系统开发和维护成本。
3. 如何进行复杂度分析 ?#
1 大 O 表示法
算法的执行时间与每行代码的执行次数成正比,用 T(n) = O(f(n)) 表示,其中 T(n) 表示算法执行总时间,
f(n) 表示每行代码执行总次数,而 n 往往表示数据的规模。这就是大 O 时间复杂度表示法。
2 时间复杂度
1)定义
算法的时间复杂度,也就是算法的时间量度。
大 O 时间复杂度表示法 实际上并不具体表示代码真正的执行时间,而是表示 代码执行时间随数据规模
增长的变化趋势,所以也叫 渐进时间复杂度,简称 时间复杂度(asymptotic time complexity)。
例子1:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function aFun() { console.log( "Hello, World!" ); return 0; // 需要执行 1 次 // 需要执行 1 次 } |
那么这个方法需要执行 2 次运算。
例子 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function bFun(n) { for ( let i = 0; i < n; i++) { console.log( "Hello, World!" ); // 需要执行 (n + 1) 次 // 需要执行 n 次 } return 0; // 需要执行 1 次 } |
那么这个方法需要执行 ( n + 1 + n + 1 ) = 2n +2 次运算。
例子 3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | function cal(n) { let sum = 0; // 1 次 let i = 1; // 1 次 let j = 1; // 1 次 for (; i <= n; ++i) { j = 1; // n 次 // n 次 for (; j <= n; ++j) { sum = sum + i * j; // n * n ,也即是 n平方次 // n * n ,也即是 n平方次 } } } |
注意,这里是二层 for 循环,所以第二层执行的是 n * n = n2 次,而且这里的循环是 ++i,和例子 2 的
是 i++,是不同的,是先加与后加的区别。
那么这个方法需要执行 ( n2 + n2 + n + n + 1 + 1 +1 ) = 2n2 +2n + 3 。
2)特点
以时间复杂度为例,由于 时间复杂度 描述的是算法执行时间与数据规模的 增长变化趋势,所以 常量、
低阶、系数 实际上对这种增长趋势不产生决定性影响,所以在做时间复杂度分析时 忽略 这些项。
所以,上面例子1 的时间复杂度为 T(n) = O(1),例子2 的时间复杂度为 T(n) = O(n),例子3 的时间复杂
度为 T(n) = O(n2)。
3 时间复杂度分析
只关注循环执行次数最多的一段代码
单段代码看高频:比如循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function cal(n) { let sum = 0; let i = 1; for (; i <= n; ++i) { sum = sum + i; } return sum; } |
执行次数最多的是 for 循环及里面的代码,执行了 n 次,所以时间复杂度为 O(n)。
加法法则:总复杂度等于量级最大的那段代码的复杂度
多段代码取最大:比如一段代码中有单循环和多重循环,那么取多重循环的复杂度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | function cal(n) { let sum_1 = 0; let p = 1; for (; p < 100; ++p) { sum_1 = sum_1 + p; } let sum_2 = 0; let q = 1; for (; q < n; ++q) { sum_2 = sum_2 + q; } let sum_3 = 0; let i = 1; let j = 1; for (; i <= n; ++i) { j = 1; for (; j <= n; ++j) { sum_3 = sum_3 + i * j; } } return sum_1 + sum_2 + sum_3; } |
上面代码分为三部分,分别求 sum_1、sum_2、sum_3 ,主要看循环部分。
第一部分,求 sum_1 ,明确知道执行了 100 次,而和 n 的规模无关,是个常量的执行时间,不能反映
增长变化趋势,所以时间复杂度为 O(1)。
第二和第三部分,求 sum_2 和 sum_3 ,时间复杂度是和 n 的规模有关的,为别为 O(n) 和 O(n2)。
所以,取三段代码的最大量级,上面例子的最终的时间复杂度为 O(n2)。
同理类推,如果有 3 层 for 循环,那么时间复杂度为 O(n3),4 层就是 O(n4)。
所以,总的时间复杂度就等于量级最大的那段代码的时间复杂度。
乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
嵌套代码求乘积:比如递归、多重循环等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | function cal(n) { let ret = 0; let i = 1; for (; i < n; ++i) { ret = ret + f(i); // 重点为 f(i) } } function f(n) { let sum = 0; let i = 1; for (; i < n; ++i) { sum = sum + i; } return sum; } |
方法 cal 循环里面调用 f 方法,而 f 方法里面也有循环。
所以,整个 cal() 函数的时间复杂度就是,T(n) = T1(n) * T2(n) = O(n*n) = O(n2) 。
多个规模求加法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function cal(m, n) { let sum_1 = 0; let i = 1; for (; i < m; ++i) { sum_1 = sum_1 + i; } let sum_2 = 0; let j = 1; for (; j < n; ++j) { sum_2 = sum_2 + j; } return sum_1 + sum_2; } |
以上代码也是求和 ,求 sum_1 的数据规模为 m、求 sum_2 的数据规模为 n,所以时间复杂度为
O(m+n)。
公式:T1(m) + T2(n) = O(f(m) + g(n)) 。
多个规模求乘法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相乘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function cal(m, n) { let sum_3 = 0; let i = 1; let j = 1; for (; i <= m; ++i) { j = 1; for (; j <= n; ++j) { sum_3 = sum_3 + i * j; } } } |
以上代码也是求和,两层 for 循环 ,求 sum_3 的数据规模为 m 和 n,所以时间复杂度为 O(m*n)。
公式:T1(m) * T2(n) = O(f(m) * g(n)) 。
4.常用的时间复杂度分析#
多项式阶:随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。
包括 O(1)(常数阶)、O(logn)(对数阶)、O(n)(线性阶)、O(nlogn)(线性对数阶)、O(n2) (平方
阶)、O(n3)(立方阶)。
除了 O(logn)、O(nlogn) ,其他的都可从上面的几个例子中看到。
下面举例说明 O(logn)(对数阶):
1 2 3 4 5 6 7 8 9 | let i=1; while (i <= n) { i = i * 2; } |
代码是从 1 开始,每次循环就乘以 2,当大于 n 时,循环结束。
其实就是高中学过的等比数列,i 的取值就是一个等比数列。在数学里面是这样子的:
20 21 22 ... 2k ... 2x = n
所以,我们只要知道 x 值是多少,就知道这行代码执行的次数了,通过 2x = n 求解 x,数学中求解得 x
= log2n 。所以上面代码的时间复杂度为 O(log2n)。
实际上,不管是以 2 为底、以 3 为底,还是以 10 为底,我们可以把所有对数阶的时间复杂度都记为
O(logn)。为什么呢?
因为对数之间是可以互相转换的,log3n = log32 * log2n,所以 O(log3n) = O(C * log2n),其中
C=log32 是一个常量。
由于 时间复杂度 描述的是算法执行时间与数据规模的 增长变化趋势,所以 常量、低阶、系数 实际上对
这种增长趋势不产生决定性影响,所以在做时间复杂度分析时 忽略 这些项。
因此,在对数阶时间复杂度的表示方法里,我们忽略对数的 “底”,统一表示为 O(logn)。
下面举例说明 O(nlogn)(对数阶):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | function aFun(n){ let i = 1; while (i <= n) i = i * 2; { } return i } function cal(n) { let sum = 0; for ( let i = 1; i <= n; ++i) { sum = sum + aFun(n); } return sum; } |
aFun 的时间复杂度为 O(logn),而 cal 的时间复杂度为 O(n),所以上面代码的时间复杂度为 T(n) =
T1(logn) * T2(n) = O(logn*n) = O(nlogn) 。
非多项式阶:随着数据规模的增长,算法的执行时间和空间占用暴增,这类算法性能极差。
包括 O(2n)(指数阶)、O(n!)(阶乘阶)。
O(2n)(指数阶)例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 | aFunc( n ) { if (n <= 1) { return 1; } else { return aFunc(n - 1) + aFunc(n - 2); } } |
参考答案:
显然运行次数,T(0) = T(1) = 1,同时 T(n) = T(n - 1) + T(n - 2) + 1,这里的 1 是其中的加法算一次执行。
显然 T(n) = T(n - 1) + T(n - 2) 是一个斐波那契数列,通过归纳证明法可以证明,当 n >= 1 时 T(n) <
(5/3)n,同时当 n > 4 时 T(n) >= (3/2)n。
所以该方法的时间复杂度可以表示为 O((5/3)n),简化后为 O(2n)。
可见这个方法所需的运行时间是以指数的速度增长的。
如果大家感兴趣,可以试下分别用 1,10,100 的输入大小来测试下算法的运行时间,相信大家会感受
到时间复杂度的无穷魅力。
5.时间复杂度分类#
时间复杂度可以分为:
最好情况时间复杂度(best case time complexity):在最理想的情况下,执行这段代码的时间复
杂度。
最坏情况时间复杂度(worst case time complexity):在最糟糕的情况下,执行这段代码的时间
复杂度。
平均情况时间复杂度(average case time complexity),用代码在所有情况下执行的次数的加权
平均值表示。也叫 加权平均时间复杂度 或者 期望时间复杂度。
均摊时间复杂度(amortized time complexity): 在代码执行的所有复杂度情况中绝大部分是低级
别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低
级别复杂度上。基本上均摊结果就等于低级别复杂度。
举例说明:
// n 表示数组 array 的长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function find(array, n, x) { let i = 0; let pos = -1; for (; i < n; ++i) { if (array[i] == x) { pos = i; break ; } } return pos; } |
find 函数实现的功能是在一个数组中找到值等于 x 的项,并返回索引值,如果没找到就返回 -1 。
最好情况时间复杂度,最坏情况时间复杂度
如果数组中第一个值就等于 x,那么时间复杂度为 O(1),如果数组中不存在变量 x,那我们就需要把整
个数组都遍历一遍,时间复杂度就成了 O(n)。所以,不同的情况下,这段代码的时间复杂度是不一样
的。
所以上面代码的 最好情况时间复杂度为 O(1),最坏情况时间复杂度为 O(n)。
平均情况时间复杂度
如何分析平均时间复杂度 ?代码在不同情况下复杂度出现量级差别,则用代码所有可能情况下执行次数
的加权平均值表示。
要查找的变量 x 在数组中的位置,有 n+1 种情况:在数组的 0~n-1 位置中和不在数组中。我们把每种
情况下,查找需要遍历的元素个数累加起来,然后再除以 n+1,就可以得到需要遍历的元素个数的平均
值,即:
省略掉系数、低阶、常量,所以,这个公式简化之后,得到的平均时间复杂度就是 O(n)。
我们知道,要查找的变量 x,要么在数组里,要么就不在数组里。这两种情况对应的概率统计起来很麻
烦,我们假设在数组中与不在数组中的概率都为 1/2。另外,要查找的数据出现在 0~n-1 这 n 个位置的
概率也是一样的,为 1/n。所以,根据概率乘法法则,要查找的数据出现在 0~n-1 中任意位置的概率就
是 1/(2n)。
因此,前面的推导过程中存在的最大问题就是,没有将各种情况发生的概率考虑进去。如果我们把每种
情况发生的概率也考虑进去,那平均时间复杂度的计算过程就变成了这样:
这个值就是概率论中的 加权平均值,也叫 期望值,所以平均时间复杂度的全称应该叫 加权平均时间复
杂度 或者 期望时间复杂度。
所以,根据上面结论推导出,得到的 平均时间复杂度 仍然是 O(n)。
均摊时间复杂度
均摊时间复杂度就是一种特殊的平均时间复杂度 (应用场景非常特殊,非常有限,这里不说)。
6.时间复杂度消耗时间排序#
常用的时间复杂度所耗费的时间从小到大依次是:
O(1) < O(logn) < (n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
7.空间复杂度分析#
时间复杂度的全称是 渐进时间复杂度,表示 算法的执行时间与数据规模之间的增长关系 。
类比一下,空间复杂度全称就是 渐进空间复杂度(asymptotic space complexity),表示 算法的存储
空间与数据规模之间的增长关系 。
定义:算法的空间复杂度通过计算算法所需的存储空间实现,算法的空间复杂度的计算公式记作:S(n) =
O(f(n)),其中,n 为问题的规模,f(n) 为语句关于 n 所占存储空间的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function print(n) { const newArr = []; // 第 2 行 newArr.length = n; // 第 3 行 for ( let i = 0; i <n; ++i) { newArr[i] = i * i; } for ( let j = n-1; j >= 0; --j) { console.log(newArr[i]) } } |
跟时间复杂度分析一样,我们可以看到,第 2 行代码中,我们申请了一个空间存储变量 newArr ,是个
空数组。第 3 行把 newArr 的长度修改为 n 的长度的数组,每项的值为 undefined ,除此之外,剩下的
代码都没有占用更多的空间,所以整段代码的空间复杂度就是 O(n)。
我们常见的空间复杂度就是 O(1)、O(n)、O(n2),像 O(logn)、O(nlogn) 这样的对数阶复杂度平时都用
不到。
8.如何掌握好复杂度分析方法 ?#
平时我们在写代码时,是用 空间换时间 还是 时间换空间,可以根据算法的时间复杂度和空间复杂度来
衡量。
9.判断一段字符串是否为回文?#
回文是指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情趣,叫做回文,也叫
回环。比如 abba,redder…
1.字符串转数组;2.用reverse()函数颠倒;3.使用join(’’)拼接成字符串
function reverseFn( str ) {
return str == str.split(',').reverse().join('')
}
10.数组去重#
1.直接双重遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | var arr = [1,2,3,3,4,3,5,3,7,5]; function removeRepetition(arr) { for ( var i = 0; i < arr.length-1; i++){ for ( var j = i+1; j < arr.length; j++){ if (arr[i]==arr[j]){ arr.splice(j,1); //console.log(arr[j]); j--; } } } return arr; } 1 2 3 4 5 6 7 8 9 10 11 12 |
2.用indexOf()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | var arr = [1,2,3,3,4,3,5,3,7,5]; var arr1 = []; function removeRepetition(arr) { for ( var i = 0;i < arr.length; i++) { if (arr1.indexOf(arr[i]) == -1){ arr1.push(arr[i]) } } return arr1; } 1 2 3 4 5 6 7 8 9 10 |
3.用fifter方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var arr = [ 'apple' , 'strawberry' , 'banana' , 'pear' , 'apple' , 'orange' , 'orange' , 'strawberry' ]; var r = arr.filter( function (element,index,self){ return self.indexOf(element) === index; }); console.log(r); 1 2 3 4 5 |
4.使用ES6的Set
1 2 3 | const removeDuplicateItems = arr => [... new Set(arr)]; removeDuplicateItems([42, 'foo' , 42, 'foo' , true , true ]);<br><br> |
参考链接
https://blog.csdn.net/qq_42946917/article/details/89024468
性能优化#
1.性能优化的几个方面?#
1.资源压缩合并,减少HTTP请求
2.非核心代码异步加载
3.利用浏览器缓存
4.使用CDN
5.预解析DNS
2.如何进行首屏优化#
1》首先对于首屏,我认为用户体验有三个阶段:
①就是页面第一个东西加载出来:用户会感觉到自己已经成功访问到这个网址了
②页面第一个含有有用信息的东西加载出来:用户会觉得能在这个网站上获取到有用的信息
③页面可以进行交互:用户进行交互体验
2》然后对前面所学的性能优化进行一下总结即可
3.什么情况会造成内存泄漏?#
避免意外的全局变量的产生(非严格模式)
称为全局变量后 就不会在函数执行完被回收掉了
避免反复运行形成大量的闭包
避免脱离的DOM元素
4.异步加载?#
动态脚本加载
defer
async
5.加载方式区别?#
defer是在html解析完毕才执行,如果有多个则按加载顺序执行
async是加载完毕后立即执行,如果是多个,执行顺序与加载顺序无关
6.浏览器缓存?#
分类
强缓存
是指在时间之内不会询问服务器是否需要缓存。
Expires(过期时间) Expries:Sun Jun 16 2019 23:55:21 GMT(服务器时间)
Cache-Control(相对时间)
协商缓存
如果本地有缓存,则需要向服务器询问是否需要使用本地缓存。
Last-Modified if-Modified-Since
Etag If-None-Matc
7.预加载?#
在开发中,可能会遇到这样的情况。有些资源不需要马上用到,但是希望尽早获取,这时候就可以使用
预加载。
预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码
开启预加载
<link rel="preload" href="http://example.com">
预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一
缺点就是兼容性不好。
8.预渲染?#
可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染
<link rel="prerender" href="http://example.com">
预渲染虽然可以提高页面的加载速度,但是要确保该页面大概率会被用户在之后打开,否则就是白白浪
费资源去渲染。
9.CDN?#
CDN 的原理是尽可能的在各个地方分布机房缓存数据,这样即使我们的根服务器远在国外,在国内的用
户也可以通过国内的机房迅速加载资源。
因此,我们可以将静态资源尽量使用 CDN 加载,由于浏览器对于单个域名有并发请求上限,可以考虑
使用多个 CDN 域名。并且对于 CDN 加载静态资源需要注意 CDN 域名要与主站不同,否则每次请求都
会带上主站的 Cookie,平白消耗流量。
10.DNS 预解析?#
DNS 解析也是需要时间的,可以通过预解析的方式来预先获得域名所对应的 IP。
<meta http-equiv='x-dns-prefetch-control' content='on'>
<link rel="dns-prefetch" href="//yuchengkai.cn">
在https协议中默认a标签不会开启预解析,因此需要手动设置meta
11.节流?#
考虑一个场景,滚动事件中会发起网络请求,但是我们并不希望用户在滚动过程中一直发起请求,而是
隔一段时间发起一次,对于这种情况我们就可以使用节流。
理解了节流的用途,我们就来实现下这个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | // func是用户传入需要防抖的函数 // wait是等待时间 const throttle = (func, wait = 50) => { // 上一次执行该函数的时间 let lastTime = 0 return function (...args) { // 当前时间 let now = + new Date() // 将当前时间和上一次执行函数时间对比 // 如果差值大于设置的等待时间就执行函数 if (now - lastTime > wait) { lastTime = now func.apply( this , args) } } } setInterval( throttle(() => { console.log(1) }, 500), 1 ) |
12.防抖?
考虑一个场景,有一个按钮点击会触发网络请求,但是我们并不希望每次点击都发起网络请求,而是当
用户点击按钮一段时间后没有再次点击的情况才去发起网络请求,对于这种情况我们就可以使用防抖。
理解了防抖的用途,我们就来实现下这个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // func是用户传入需要防抖的函数 // wait是等待时间 const debounce = (func, wait = 50) => { // 缓存一个定时器id let timer = 0 // 这里返回的函数是每次用户实际调用的防抖函数 // 如果已经设定过定时器了就清空上一次的定时器 // 开始一个新的定时器,延迟执行用户传入的方法 return function (...args) { if (timer) clearTimeout(timer) timer = setTimeout(() => { func.apply( this , args) }, wait) } } |
13.懒执行?#
懒执行就是将某些逻辑延迟到使用时再计算。该技术可以用于首屏优化,对于某些耗时逻辑并不需要在
首屏就使用的,就可以使用懒执行。懒执行需要唤醒,一般可以通过定时器或者事件的调用来唤醒。
14.懒加载?#
懒加载就是将不关键的资源延后加载。
懒加载的原理就是只加载自定义区域(通常是可视区域,但也可以是即将进入可视区域)内需要加载的
东西。对于图片来说,先设置图片标签的 src 属性为一张占位图,将真实的图片资源放入一个自定义属
性中,当进入自定义区域时,就将自定义属性替换为 src 属性,这样图片就会去下载资源,实现了图片
懒加载。
懒加载不仅可以用于图片,也可以使用在别的资源上。比如进入可视区域才开始播放视频等等。
15.图片优化?#
计算图片大小
对于一张 100 * 100 像素的图片来说,图像上有 10000 个像素点,如果每个像素的值是 RGBA 存储的
话,那么也就是说每个像素有 4 个通道,每个通道 1 个字节(8 位 = 1个字节),所以该图片大小大概
为 39KB(10000 * 1 * 4 / 1024)。
但是在实际项目中,一张图片可能并不需要使用那么多颜色去显示,我们可以通过减少每个像素的调色
板来相应缩小图片的大小。
了解了如何计算图片大小的知识,那么对于如何优化图片,想必大家已经有 2 个思路了:
减少像素点
减少每个像素点能够显示的颜色
16.图片加载优化?#
1.不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替。
2.对于移动端来说,屏幕宽度就那么点,完全没有必要去加载原图浪费带宽。一般图片都用 CDN 加载,
可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图片。2。 对于移动端来说,屏幕宽度就那么
点,完全没有必要去加载原图浪费带宽。一般图片都用 CDN 加载,可以计算出适配屏幕的宽度,然后
去请求相应裁剪好的图片。
3.小图使用 base64 格式
4.将多个图标文件整合到一张图片中(雪碧图)
5.选择正确的图片格式:
1.对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP 格式具有更好的图像数据压缩算
法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好
2.小图使用 PNG,其实对于大部分图标这类图片,完全可以使用 SVG 代替
3.照片使用 JPEG
17.js css 顺序对前端优化影响?#
上面我们说到了整个渲染流程,但是没有说到 css 和 js 对渲染的影响。渲染树的构成必须要 DOM 树和
CSSOM 树的,所以尽快的构建 CSSOM 树是一个重要的优化手段,如果 css 文件放在尾部,那么整个过
程就是一个串行的过程先解析了 dom,再去解析 css。所以 css 我们一般都是放在头部,这样 DOM 树
和 CSSOM 树的构建是同步进行的。
再来看 js,因为 js 的运行会阻止 DOM 树的渲染的,所以一旦我们的 js 放在了头部,而且也没有异步加
载这些操作的话,js 一旦一直在运行,DOM 树就一直构建不出来,那么页面就会一直出现白屏界面,
所以一般我们会把 js 文件放在尾部。当然放到尾部也不是就没有问题了,只是问题相对较小,放到尾部
的 js 文件如果过大,运行时间长,代码加载时,就会有大量耗时的操作造成页面不可点击,这就是另一
个问题,但这肯定比白屏要好,白屏是什么页面都没有,这种是页面有了只是操作不流畅。
js 脚本放在尾部还有一个原因,有时候 js 代码会有操作 dom 节点的情况,如果放在头部执行,DOM树
还没有构建,拿不到 DOM 节点但是你又去使用就会出现报错情况,错误没处理好的话页面会直接崩掉
18.重排重绘为什么会影响渲染,如何避免?#
重排和重绘为什么会影响渲染,哪个影响更大,如何避免是经常被问到的一道题目,我们先来说一下重
绘
重绘
重绘指的是不影响界面布局的操作,比如更改颜色,那么根据上面的渲染讲解我们知道,重绘之后我们
只需要在重复进行一下样式计算,就可以直接渲染了,对浏览器渲染的影响相对较小
重排
重排指的是影响界面布局的操作,比如改变宽高,隐藏节点等。对于重排就不是一个重新计算样式那么
简单了,因为改变了布局,根据上面的渲染流程来看涉及到的阶段有样式计算,布局树重新生成,分层
树重新生成,所以重排对浏览器的渲染影响是比较高的
避免方法
1.js 尽量减少对样式的操作,能用 css 完成的就用 css
2.对 dom 操作尽量少,能用 createDocumentFragment 的地方尽量用
3.如果必须要用 js 操作样式,能合并尽量合并不要分多次操作
4.resize 事件 最好加上防抖,能尽量少触发就少触发
5.加载图片的时候,提前写好宽高
19.何时缓存在memory,合适缓存在dist?#
这个问题网上很少找的到标准答案,大家一致的说法是js,图片文件浏览器会自动保存在memory中,css
文件因为不常修改保存在dist里面,我们可以打开掘金网站,很大一部分文件都是按照这个规则来的,
但是也有少数js文件也是缓存在dist里面。所以他的存放机制到底是什么样了?我带着这个疑问查了好多
文章,虽然最后没有确切找到答案,但是一个知乎的回答可以给我们提供思路,下面引用一个知乎回答
者一段话
第一个现象(以图片为例):访问-> 200 -> 退出浏览器再进来-> 200(from disk cache) -> 刷新 ->
200(from memory cache)。总结: 会不会是chrome很聪明的判断既然已经从disk拿来了, 第二次
就内存拿吧 快。(笑哭)
第二个现象(以图片为例):只要图片是base64 我看都是from memroy cache。总结: 解析渲染图片
这么费劲的事情,还是做一次然后放到内存吧。用的时候直接拿
第三个现象(以js css为例):个人在做静态测试的发现,大型的js css文件都是直接disk cache。结:
chrome会不会说 我去 你这么大太占地方了。你就去硬盘里呆着吧。慢就慢点吧。
第四个现象:隐私模式下,几乎都是 from memroy cache。总结: 隐私模式 是吧。我不能暴露你
东西,还是放到内存吧。你关,我死。
上面几点是虽然很幽默,但是却可以从中找到一部分答案,但是我觉得另一个知乎回答我更赞同
浏览器运行的时候也是由几个进程协作的,所以操作系统为了节省内存,会把一部分内存里的资源
交换回磁盘的交换区,当然交换是有策略的,比如最常用的就是LRU。
什么时候存dist,什么时候存memoey都是在浏览器控制下的,memory不够了可能就会考虑去存dist
了,所以经过上面所说我自己总结结果如下
大一点的文件会缓存在dist里面,因为内存也是有限的,磁盘的空间更大
小一点文件js,图片存的是memory
css文件一般存在dist
特殊情况memory大小是有限制的,浏览器也会根据自己的内置算法,把一部分js文件存到dist里
面
20.CSS选择符优化#
在大多数人的观念中,都觉得浏览器对 CSS选择符的解析式从左往右进行的,例如
#toc A { color: #444; }这样一个选择符,如果是从右往左解析则效率会很高,因为第一个 ID选择基本上
就把查找的范围限定了,但实际上浏览器对选择符的解析是从右往左进行的。如上面的选择符,浏览器
必须遍历查找每一个 A标签的祖先节点,效率并不像之前想象的那样高。根据浏览器的这一行为特点,
在写选择符的时候需要注意很多事项,有兴趣的童鞋可以去了解一下。
CDN加速
CDN(contentdistribute network,内容分发网络)的本质仍然是一个缓存,而且将数据缓存在离用户
最近的地方,使用户以最快速度获取数据,即所谓网络访问第一跳,如下图。
由于CDN部署在网络运营商的机房,这些运营商又是终端用户的网络服务提供商,因此用户请求路由的
第一跳就到达了CDN服务器,当CDN中存在浏览器请求的资源时,从CDN直接返回给浏览器,最短路径
返回响应,加快用户访问速度,减少数据中心负载压力。
CDN缓存的一般是静态资源,如图片、文件、CSS、script脚本、静态网页等,但是这些文件访问频度很
高,将其缓存在CDN可极大改善网页的打开速度。
反向代理
传统代理服务器位于浏览器一侧,代理浏览器将http请求发送到互联网上,而反向代理服务器位于网站
机房一侧,代理网站web服务器接收http请求。
参考链接
https://blog.csdn.net/qianyu6200430/article/details/109712717
https://blog.csdn.net/qq_37674616/article/details/86490686
https://www.cnblogs.com/liubingyjui/p/10095633.html
Ajax#
1.什么是ajax?ajax作用是什么?#
AJAX = 异步 JavaScript 和 XML。 AJAX 是一种用于创建快速动态网页的技术。 通过在后台与服务器进
行少量数据交换,AJAX 可以使网页实现异步更新.
2.为什么要用ajax:#
Ajax应用程序的优势在于:
\1. 通过异步模式,提升了用户体验
\2. 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用
\3. Ajax引擎在客户端运行,承担了一部分本来由服务器承担的工作,从而减少了大用户量下的服务器负
载。
3.AJAX最大的特点是什么。#
Ajax可以实现动态不刷新(局部刷新)
就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了
在网络上发送那些没有改变过的信息。
4.请介绍一下XMLHttprequest对象。#
Ajax的核心是JavaScript对象XmlHttpRequest。该对象在Internet Explorer 5中首次引入,它是一种支
持异步请求的技术。简而言之,XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响
应,而不阻塞用户。通过XMLHttpRequest对象,Web开发人员可以在页面加载以后进行页面的局部更
新。
5.AJAX技术体系的组成部分有哪些。#
HTML,css,dom,xml,xmlHttpRequest,javascript
6.工作当中会和后台交互吗? 那你能说说封装好的 ajax里的几个参数吗 ?#
url: 发送请求的地址。
type: 请求方式(post或get)默认为get。
async: 同步异步请求,默认true所有请求均为异步请求。
timeout : 超时时间设置,单位毫秒
data:要求为Object或String类型的参数,发送到服务器的数据
cache:默认为true(当dataType为script时,默认为false), 设置为false将不会从浏览器缓存中加载请
求信息。
dataType: 预期服务器返回的数据类型。
可用的类型如下:
xml:返回XML文档,可用JQuery处理。
html:返回纯文本HTML信息;包含的script标签会在插入DOM时执行。
script:返回纯文本JavaScript代码。不会自动缓存结果。
json:返回JSON数据。
jsonp:JSONP格式。使用JSONP形式调用函数时,例如myurl?callback=?,JQuery将自动替换后一个“?”
为正确的函数名,以执行回调函数。
text:返回纯文本字符串。
success:请求成功后调用的回调函数,有两个参数。
(1) 由服务器返回,并根据dataType参数进行处理后的数据。
(2) 描述状态的字符串。
error:要求为Function类型的参数,请求失败时被调用的函数。该函数有3个参数
(1) XMLHttpRequest对象
(2) 错误信息
(3) 捕获的错误对象(可选)
complete :function(XMLHttpRequest,status){ //请求完成后最终执行参数
7.Ajax的实现流程是怎样的?#
Ajax的实现流程是怎样的?
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | <script type= "text/javascript" > var httpRequest; function checkUsername() { if (window.XMLHttpRequest) { //在IE6以上的版本以及其他内核的浏览器(Mozilla)等 httpRequest = new XMLHttpRequest(); } else if (window.ActiveXObject) { //在IE6以下的版本 httpRequest = new ActiveXObject(); } //创建http请求 httpRequest.open( "POST" , "Servlet1" , true ); //因为我使用的是post方式,所以需要设置消息头 httpRequest.setRequestHeader( "Content-type" , "application/x-www-formurlencoded" ); //指定回调函数 httpRequest.onreadystatechange = response22; //得到文本框的数据 var name = document.getElementById( "username" ).value; //发送http请求,把要检测的用户名传递进去 httpRequest.send( "username=" + name); } function response22() { //判断请求状态码是否是4【数据接收完成】 if (httpRequest.readyState==4) { //再判断状态码是否为200【200是成功的】 if (httpRequest.status==200) { //得到服务端返回的文本数据 var text = httpRequest.responseText; //把服务端返回的数据写在div上 var div = document.getElementById( "result" ); div.innerText = text; } } } </script> |
8.AJAX请求总共有多少种CALLBACK#
AJAX请求总共有多少种CALLBACK
Ajax请求总共有八种Callback
onSuccess
onFailure
onUninitialized
onLoading
onLoaded
onInteractive
onComplete
onException
9.AJAX有哪些有点和缺点?#
AJAX有哪些有点和缺点?#
优点:
1、最大的一点是页面无刷新,用户的体验非常好。
2、使用异步方式与服务器通信,具有更加迅速的响应能力。
3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器
和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,
可以最大程度的减少冗余请求,和响应对服务器造成的负担。
4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。
缺点:
1、ajax不支持浏览器back按钮。
2、安全问题 AJAX暴露了与服务器交互的细节。
3、对搜索引擎的支持比较弱。
4、破坏了程序的异常机制。
5、不容易调试。
10.Ajax 解决浏览器缓存问题?#
Ajax 解决浏览器缓存问题?#
1、在ajax发送请求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0")。
2、在ajax发送请求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache")。
3、在URL后面加上一个随机数: "fresh=" + Math.random();。
4、在URL后面加上时间戳:"nowtime=" + new Date().getTime();。
5、如果是使用jQuery,直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会
执行这条语句就是不需要保存缓存记录。
参考链接
https://zhuanlan.zhihu.com/p/98288927
https://segmentfault.com/a/1190000013291898
https://blog.csdn.net/dkh_321/article/details/79311367
ES6#
1.es5和es6的区别,说一下你所知道的es6#
ECMAScript5,即ES5,是ECMAScript的第五次修订,于2009年完成标准化ECMAScript6,即ES6,是
ECMAScript的第六次修订,于2015年完成,也称ES2015ES6是继ES5之后的一次改进,相对于ES5更加
简洁,提高了开发效率ES6新增的一些特性:
1)let声明变量和const声明常量,两个都有块级作用域ES5中是没有块级作用域的,并且var有变量提
升,在let中,使用的变量一定要进行声明
2)箭头函数ES6中的函数定义不再使用关键字function(),而是利用了()=>来进行定义
3)模板字符串模板字符串是增强版的字符串,用反引号标识,可以当作普通字符串使用,也可以用来定
义多行字符串
4)解构赋值ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值
5)for of循环for...of循环可以遍历数组、Set和Map结构、某些类似数组的对象、对象,以及字符串
6)import、export导入导出ES6标准中,Js原生支持模块(module)。将JS代码分割成不同功能的小块进
行模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导
入的方式可以在其他地方使用
7)set数据结构Set数据结构,类似数组。所有的数据都是唯一的,没有重复的值。它本身是一个构造函
数
8)... 展开运算符可以将数组或对象里面的值展开;还可以将多个值收集为一个变量
9)修饰器 @decorator是一个函数,用来修改类甚至于是方法的行为。修饰器本质就是编译时执行的函
数
10)class 类的继承ES6中不再像ES5一样使用原型链实现继承,而是引入Class这个概念11)async、
await使用 async/await, 搭配promise,可以通过编写形似同步的代码来处理异步流程, 提高代码的简洁性
和可读性async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成
12)promisePromise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理、强
大
13)SymbolSymbol是一种基本类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参
数,该函数返回的symbol是唯一的
14)Proxy代理使用代理(Proxy)监听对象的操作,然后可以做一些相应事情
2.var、let、const之间的区别#
var声明变量可以重复声明,而let不可以重复声明
var是不受限于块级的,而let是受限于块级
var会与window相映射(会挂一个属性),而let不与window相映射
var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错
const声明之后必须赋值,否则会报错
const定义不可变的量,改变了就会报错
const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错
3.使用箭头函数应注意什么?#
(1)用了箭头函数,this就不是指向window,而是父级(指向是可变的)
(2)不能够使用arguments对象
(3)不能用作构造函数,这就是说不能够使用new命令,否则会抛出一个错误
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数
4.ES6的模板字符串有哪些新特性?并实现一个类模板字符串的功能#
基本的字符串格式化。
将表达式嵌入字符串中进行拼接。
用${}来界定在ES5时我们通过反斜杠()来做多行字符串或者字符串一行行拼接。
ES6反引号就能解决类模板字符串的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 | let name = 'web' ; let age = 10; let str = '你好,${name} 已经 ${age}岁了' str = str.replace(/\$\{([^}]*)\}/g, function (){ return eval(arguments[1]); }) console.log(str); //你好,web 已经 10岁了 |
5.介绍下 Set、Map的区别?#
应用场景:Set用于数据重组,Map用于数据储存
Set:
(1)成员不能重复
(2)只有键值没有键名,类似数组
(3)可以遍历,方法有add, delete,has
Map:
(1)本质上是健值对的集合,类似集合
(2)可以遍历,可以跟各种数据格式转换
6.ECMAScript 6 怎么写 class ,为何会出现 class?#
ES6的class可以看作是一个语法糖,它的绝大部分功能ES5都可以做到,新的class写法只是让对象原型
的写法更加清晰、更像面向对象编程的语法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //定义类 class Point { constructor(x,y) { //构造方法 this .x = x; //this关键字代表实例对象 this .y = y; } toString() { return '(' + this .x + ',' + this .y + ')' ; } } |
7.Promise构造函数是同步执行还是异步执行,那么 then 方法呢?#
promise构造函数是同步执行的,then方法是异步执行的
8.setTimeout、Promise、Async/Await 的区别#
事件循环中分为宏任务队列和微任务队列
其中setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行promise.then里的回调函数会
放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行async函数表示函数里面可能
会有异步方法,await后面跟一个表达式
async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执
行栈让同步代码先执行
9.promise有几种状态,什么时候会进入catch?#
三个状态:
pending、fulfilled、reject
两个过程:
padding -> fulfilled、padding -> rejected当pending为rejectd时,会进入catch
10.使用结构赋值,实现两个变量的值的交换#
let a = 1;let b = 2;
[a,b] = [b,a];
11.Promise 中reject 和 catch 处理上有什么区别#
reject 是用来抛出异常,catch 是用来处理异常
reject 是 Promise 的方法,而 catch 是 Promise 实例的方法
reject后的东西,一定会进入then中的第二个回调,如果then中没有写第二个回调,则进入catch
网络异常(比如断网),会直接进入catch而不会进入then的第二个回调
12.理解 async/await以及对Generator的优势#
async await 是用来解决异步的,async函数是Generator函数的语法糖
使用关键字async来表示,在函数内部使用 await 来表示异步
async函数返回一个 Promise 对象,可以使用then方法添加回调函数
当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句
async较Generator的优势:
(1)内置执行器。Generator 函数的执行必须依靠执行器,而 Aysnc 函数自带执行器,调用方式跟普
通函数的调用一样
(2)更好的语义。async 和 await 相较于 * 和 yield 更加语义化
(3)更广的适用性。yield命令后面只能是 Thunk 函数或 Promise对象,async函数的await后面可以是
Promise也可以是原始类型的值
(4)返回值是 Promise。async 函数返回的是 Promise 对象,比Generator函数返回的Iterator对象方
便,可以直接使用 then() 方法进行调用
参考资料
https://zhuanlan.zhihu.com/p/102442557
jQuery#
1.jQuery库中的$()是什么?#
()函数是jQuery()函数的别称,()函数是jQuery()函数的别称,()函数用于将任何对象包裹成 jQuery对象,接着被允许调用定义在
jQuery对象上的多个不同方法。甚至可以将一个选择器字符串传入$()函数,它会返回一个包含所有匹配
的DOM元素数组的jQuery对象。这个问题我已经见过好几次被提及,尽管它非常基础,它经常被用来区
分一个开发人员是否了解jQuery。
2.网页上有5个div元素,如何使用 jQuery来选择它们?#
jQuery支持不同类型的选择器,例如ID选择器、class选择器、标签选择器。鉴于这个问题没提到ID和
class,可以用标签选择器来选择所有的div 元素。jQuery代码:$("div"),这样会返回一个包含所有5个
div标签的jQuery 对象。
3.$(this) 和 this 关键字在 jQuery 中有何不同?#
这对于很多java零基础学jQuery的初学者来说是一个棘手的问题,其实是个简单的问题。$(this) 返回一
个jQuery对象,你可以对它调用多个 jQuery方法,比如用text()获取文本,用val()获取值等等。而this代
表当前元素,它是JavaScript关键词中的一个,表示上下文中的当前DOM元素。你不能对它调用 jQuery
方法,直到它被 ()函数包裹,例如()函数包裹,例如(this)。
4.使用CDN加载 jQuery库的主要优势是什么?#
除了报错节省服务器带宽以及更快的下载速度这许多的好处之外, 最重要的是,如果浏览器已经从同一个
CDN下载类相同的jQuery版本, 那么它就不会再去下载它一次,因此今时今日,许多公共的网站都将
jQuery用于用户交互和动画, 如果浏览器已经有了下载好的jQuery库,网站就能有非常好的展示机会。
5.jQuery中的方法链是什么?使用方法链有什么好处?#
方法链是对一个方法返回的结果调用另一个方法,这使得代码简洁明了,同时由于只对DOM进行了一轮
查找,性能方面更加出色。
6.如何将一个HTML元素添加到DOM树中的?#
可以用 jQuery方法appendTo()将一个HTML元素添加到DOM树中。这是jQuery提供的众多操控DOM的
方法中的一个。可以通过appendTo()方法在指定的DOM元素末尾添加一个现存的元素或者一个新的
HTML元素。
7.说出jQuery中常见的几种函数以及他们的含义是什么?#
(1)get()取得所有匹配的DOM元素集合;
(2)get(index)取得其中一个匹配的元素.index表示取得第几个匹配的元素;
(3)append(content)向每个匹配的元素内部追加内容;
(4)after(content)在每个匹配的元素之后插入内容;
(5)html()/html(var)取得或设置匹配元素的html内容;
(6)find(expr)搜索所有与指定表达式匹配的元素;
(7)bind(type,[data],fn)为每个匹配元素的特定事件绑定事件处理函数;
(8)empty()删除匹配的元素集合中所有的子节点;
(9)hover(over,out)一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法;
(10)attr(name)取得第一个匹配元素的属性值。
8.jQuery 能做什么?#
获取页面的元素;修改页面的外观;改变页面大的内容;响应用户的页面操作;为页面添加动态效果;
无需刷新页面,即可以从服务器获取信息;简化常见的javascript任务。
9.jquery中的选择器和CSS中的选择器有区别吗?#
jQuery选择器支持CSS里的选择器,jQuery选择器可用来添加样式和添加相应的行为,CSS中的选择器
是只能添加相应的样式。
10.jQuery的特点都有什么?#
jQuery的核心特性可以总结为:具有独特的链式语法和短小清晰的多功能接口;具有高效灵活的CSS选
择器,并且可对CSS选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件。jQuery兼容各种主流浏
览器,如IE 6.0+、FF 1.5+、Safari 2.0+、Opera 9.0+等。
参考资料
https://www.wkcto.com/article/detail/649
React#
1.什么是React?#
React 是 Facebook 在 2011 年开发的前端 JavaScript 库。
它遵循基于组件的方法,有助于构建可重用的UI组件。
它用于开发复杂和交互式的 Web 和移动 UI。
尽管它仅在 2015 年开源,但有一个很大的支持社区。
2.React有什么特点?#
它使用虚拟DOM而不是真正的DOM。
它可以用服务器端渲染。
它遵循单向数据流或数据绑定。
3.列出React的一些主要优点。#
它提高了应用的性能
可以方便地在客户端和服务器端使用
由于 JSX,代码的可读性很好
React 很容易与 Meteor,Angular 等其他框架集成
使用React,编写UI测试用例变得非常容易
4.React有哪些限制?#
React 只是一个库,而不是一个完整的框架
它的库非常庞大,需要时间来理解
新手程序员可能很难理解
编码变得复杂,因为它使用内联模板和 JSX
5.什么是JSX?#
JSX 是J avaScript XML 的简写。是 React 使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的
模板语法。这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能。下面是
JSX的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 | render(){ return ( <div> <h1> Hello World from Edureka!!</h1> </div> ); } |
6.你了解 Virtual DOM 吗?解释一下它的工作原理。#
Virtual DOM 是一个轻量级的 JavaScript 对象,它最初只是 real DOM 的副本。它是一个节点树,它将
元素、它们的属性和内容作为对象及其属性。 React 的渲染函数从 React 组件中创建一个节点树。然后
它响应数据模型中的变化来更新该树,该变化是由用户或系统完成的各种动作引起的。
Virtual DOM 工作过程有三个简单的步骤。
每当底层数据发生改变时,整个 UI 都将在 Virtual DOM 描述中重新渲染。
然后计算之前 DOM 表示与新表示的之间的差异。
完成计算后,将只用实际更改的内容更新 real DOM。
7.为什么浏览器无法读取JSX?#
浏览器只能处理 JavaScript 对象,而不能读取常规 JavaScript 对象中的 JSX。所以为了使浏览器能够读
取 JSX,首先,需要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给
浏览器。
8.如何理解“在React中,一切都是组件”这句话?#
组件是 React 应用 UI 的构建块。这些组件将整个 UI 分成小的独立并可重用的部分。每个组件彼此独
立,而不会影响 UI 的其余部分。
9.解释 React 中 render() 的目的。#
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果
需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 form、group、div 等。此函数
必须保持纯净,即必须每次调用时都返回相同的结果。
10.什么是 Props?#
Props 是 React 中属性的简写。它们是只读组件,必须保持纯,即不可变。它们总是在整个应用中从父
组件传递到子组件。子组件永远不能将 prop 送回父组件。这有助于维护单向数据流,通常用于呈现动
态生成的数据。
11.React中的状态是什么?它是如何使用的?#
状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对
象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state() 访问它们。
12.React组件生命周期的阶段是什么?#
React 组件的生命周期有三个不同的阶段:
初始渲染阶段:这是组件即将开始其生命之旅并进入 DOM 的阶段。
更新阶段:一旦组件被添加到 DOM,它只有在 prop 或状态发生变化时才可能更新和重新渲染。这些只
发生在这个阶段。
卸载阶段:这是组件生命周期的最后阶段,组件被销毁并从 DOM 中删除。
13.详细解释 React 组件的生命周期方法。#
componentWillMount() – 在渲染之前执行,在客户端和服务器端都会执行。
componentDidMount() – 仅在第一次渲染后在客户端执行。
componentWillReceiveProps() – 当从父类接收到 props 并且在调用另一个渲染器之前调用。
shouldComponentUpdate() – 根据特定条件返回 true 或 false。如果你希望更新组件,请返回true 否
则返回 false。默认情况下,它返回 false。
componentWillUpdate() – 在 DOM 中进行渲染之前调用。
componentDidUpdate() – 在渲染发生后立即调用。
componentWillUnmount() – 从 DOM 卸载组件后调用。用于清理内存空间。
14.React中的事件是什么?#
在 React 中,事件是对鼠标悬停、鼠标单击、按键等特定操作的触发反应。处理这些事件类似于处理
DOM 元素中的事件。但是有一些语法差异,如:
用驼峰命名法对事件命名而不是仅使用小写字母。
事件作为函数而不是字符串传递。
事件参数重包含一组特定于事件的属性。每个事件类型都包含自己的属性和行为,只能通过其事件处理
程序访问。
15.React中的合成事件是什么?#
合成事件是围绕浏览器原生事件充当跨浏览器包装器的对象。它们将不同浏览器的行为合并为一个
API。这样做是为了确保事件在不同浏览器中显示一致的属性。
16.列出一些应该使用 Refs 的情况。#
需要管理焦点、选择文本或媒体播放时
触发式动画
与第三方 DOM 库集成
17.什么是高阶组件(HOC)?#
高阶组件是重用组件逻辑的高级方法,是一种源于 React 的组件模式。 HOC 是自定义组件,在它之内
包含另一个组件。它们可以接受子组件提供的任何动态,但不会修改或复制其输入组件中的任何行为。
你可以认为 HOC 是“纯(Pure)”组件。
18.你能用HOC做什么?#
代码重用,逻辑和引导抽象
渲染劫持
状态抽象和控制
Props 控制
19.什么是纯组件?#
纯(Pure) 组件是可以编写的最简单、最快的组件。它们可以替换任何只有 render() 的组件。这些组
件增强了代码的简单性和应用的性能。
20.React 中 key 的重要性是什么?#
key 用于识别唯一的 Virtual DOM 元素及其驱动 UI 的相应数据。它们通过回收 DOM 中当前所有的元素
来帮助 React 优化渲染。这些 key 必须是唯一的数字或字符串,React 只是重新排序元素而不是重新渲
染它们。这可以提高应用程序的性能。
21.什么是React 路由?#
React 路由是一个构建在 React 之上的强大的路由库,它有助于向应用程序添加新的屏幕和流。这使
URL 与网页上显示的数据保持同步。它负责维护标准化的结构和行为,并用于开发单页 Web 应用。
React 路由有一个简单的API。
22.为什么需要 React 中的路由?#
Router 用于定义多个路由,当用户定义特定的 URL 时,如果此 URL 与 Router 内定义的任何 “路由” 的
路径匹配,则用户将重定向到该特定路由。所以基本上我们需要在自己的应用中添加一个 Router 库,
允许创建多个路由,每个路由都会向我们提供一个独特的视图。
23.列出 React Router 的优点。#
就像 React 基于组件一样,在 React Router v4 中,API 是 ‘All About Components’。可以将 Router 可
视化为单个根组件(BrowserRouter),其中我们将特定的子路由(route)包起来。
无需手动设置历史值:在 React Router v4 中,我们要做的就是将路由包装在 BrowserRouter 组件中。
包是分开的:共有三个包,分别用于 Web、Native 和 Core。这使我们应用更加紧凑。基于类似的编码
风格很容易进行切换。
24.类组件和函数组件之间有什么区别?#
类组件( Class components )
无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props 。
所有 React 组件都必须是纯函数,并禁止修改其自身 props 。
React是单项数据流,父组件改变了属性,那么子组件视图会更新。
属性 props 是外界传递过来的,状态 state 是组件本身的,状态可以在组件中任意修改
组件的属性和状态改变都会更新视图。
函数组件(functional component)
函数组件接收一个单一的 props 对象并返回了一个React元素
区别
函数组件和类组件当然是有区别的,而且函数组件的性能比类组件的性能要高,因为类组件使用的时候
要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。
25.state 和 props有什么区别?#
state 和 props都是普通的JavaScript对象。尽管它们两者都具有影响渲染输出的信息,但它们在组件方
面的功能不同。即
props 是一个从外部传进组件的参数,主要作为就是从父组件向子组件传递数据,它具有可读性和不变
性,只能通过外部组件主动传入新的 props 来重新渲染子组件,否则子组件的 props 以及展现形式不会
改变。
state 的主要作用是用于组件保存、控制以及修改自己的状态,它只能在 constructor 中初始化,它算是
组件的私有属性,不可通过外部访问和修改,只能通过组件内部的 this.setState 来修改,修改 state 属
性会导致组件的重新渲染。
26.constructor中super与props参数一起使用的目的是什么?#
在调用方法之前,子类构造函数无法使用 this 引用 super() 。
在ES6中,在子类的 constructor 中必须先调用 super 才能引用 this 。
在 constructor 中可以使用 this.props
27.什么是受控组件?#
在HTML当中,像 input , textarea , 和 select 这类表单元素会维持自身状态,并根据用户输入进行更
新。但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。
非受控组件
非受控组件,即组件的状态不受React控制的组件,例如下边这个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import React, { Component } from 'react' ; import ReactDOM from 'react-dom' ; class Demo1 extends Component { render() { return ( <input /> ) } } ReactDOM.render(<Demo1/>, document.getElementById( 'content' )) |
在这个最简单的输入框组件里,我们并没有干涉input中的value展示,即用户输入的内容都会展示在上面。
如果我们通过props给组件设置一个初始默认值,defaultValue属性是React内部实现的一个属性,目的类
似于input的placeholder属性。
受控组件
同样的,受控组件就是组件的状态受React控制。上面提到过,既然通过设置input的value属性, 无法改
变输入框值,那么我们把它和state结合在一起,再绑定onChange事件,实时更新value值就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class Demo1 extends Component { constructor(props) { super (props); this .state = { value: props.value } } handleChange(e) { this .setState({ value: e.target.value }) } render() { return ( <input value={ this .state.value} onChange={e => this .handleChange(e)}/> ) } } |
28.使用React Hooks有什么优势?#
hooks 是react 16.8 引入的特性,他允许你在不写class的情况下操作state 和react的其他特性。
hooks 只是多了一种写组件的方法,使编写一个组件更简单更方便,同时可以自定义hook把公共的逻辑
提取出来,让逻辑在多个组件之间共享。
Hook 是什么
Hook 是什么? Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,useState 是允许你
在 React 函数组件中添加 state 的 Hook。稍后我们将学习其他 Hook。
什么时候我会用 Hook? 如果你在编写函数组件并意识到需要向其添加一些 state,以前的做法是必须将
其它转化为 class。现在你可以在现有的函数组件中使用 Hook。
ReactHooks的优点
无需复杂的DOM结构
简洁易懂
29.React中的StrictMode是什么?#
React的StrictMode是一种帮助程序组件,可以帮助您编写更好的react组件,您可以使用包装一些组
件, 并且基本上可以:
验证内部组件是否遵循某些推荐做法,如果不在控制台中,则会发出警告。
验证不赞成使用的方法,如果使用了严格模式,则会在控制台中警告您。
通过识别潜在风险来帮助您预防某些副作用。
30.React context是什么?#
React文档官网并未对 Context 给出“是什么”的定义,更多是描述使用的 Context 的场景,以及如何使用
Context 。
官网对于使用 Context 的场景是这样描述的:
In Some Cases, you want to pass data through the component tree without having to pass the
props down manuallys at every level. you can do this directly in React with the powerful "context"
API.
简单说就是,当你不想在组件树中通过逐层传递 props 或者 state 的方式来传递数据时,可以使用
Context 来实现 跨层级 的组件数据传递。
使用props或者state传递数据,数据自顶下流。
使用 Context ,可以跨越组件进行数据传递。
31.React Fiber是什么?#
React Fiber 并不是所谓的纤程(微线程、协程),而是一种基于浏览器的单线程调度算法,背后的支持
API 是大名鼎鼎的:requestIdleCallback。
Fiberl是一种将 recocilation (递归 diff),拆分成无数个小任务的算法;它随时能够停止,恢复。停止
恢复的时机取决于当前的一帧(16ms)内,还有没有足够的时间允许计算。
32.react diff 原理#
把树形结构按照层级分解,只比较同级元素。
给列表结构的每个单元添加唯一的 key 属性,方便比较。
React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字) 合并操作,调用
component 的 setState 方法的时候, React 将其标记为 dirty.
到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制. 选择性子树渲染。开发人员
可以重写 shouldComponentUpdate 提高 diff 的性能。
33.setState 和 replaceState 的区别#
setState 是修改其中的部分状态,相当于 Object.assign,只是覆盖,
不会减少原来的状态
replaceState 是完全替换原来的状态,相当于赋值,将原来的 state 替换为另一个对象,如果新状态属
性减少,那么 state 中就没有这个状态了
34.React 中有三种构建组件的方式#
React.createClass()、ES6 class 和无状态函数。
35.应该在 React 组件的何处发起 Ajax 请求#
在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被
添加到 DOM)时执行,在组件的生命周期中仅会执行一次。
更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个
未挂载的组件上调用 setState,这将不起作用。
在 componentDidMount 中发起网络请求将保证这有一个组件可以更新了。
参考资料
https://blog.csdn.net/eyeofangel/article/details/88797314
https://zhuanlan.zhihu.com/p/91725031
https://www.jianshu.com/p/7b07550699c9
Vue#
1.vue 优点?#
轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb;
简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
双向数据绑定:保留了 angular 的特点,在数据操作方面更为简单;
组件化:保留了 react 的优点,实现了 html 的封装和重用,在构建单页面应用方面有着独特的优势;
视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完
成相关操作;
虚拟 DOM:dom 操作是非常耗费性能的, 不再使用原生的 dom 操作节点,极大解放 dom 操作,但
具体操作的还是 dom 不过是换了另一种方式;
运行速度更快: 相比较与 react 而言,同样是操作虚拟 dom,就性能而言,vue 存在很大的优势。
2.vue 父组件向子组件传递数据?#
通过 props
3.子组件像父组件传递事件?#
$emit 方法
4.v-show 和 v-if 指令的共同点和不同点?#
共同点:都能控制元素的显示和隐藏;
不同点:实现本质方法不同,v-show 本质就是通过控制 css 中的 display 设置为 none,控制隐藏,只
会编译一次;v-if 是动态的向 DOM 树内添加或者删除 DOM 元素,若初始值为 false,就不会编译了。
而且 v-if 不停的销毁和创建比较消耗性能。
总结:如果要频繁切换某节点,使用 v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某
节点使用 v-if(初始渲染开销较小,切换开销比较大)。
5. 如何让 CSS 只在当前组件中起作用?#
在组件中的 style 前面加上 scoped
6. 的作用是什么?#
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
7.如何获取 dom?#
ref="domName" 用法:this.$refs.domName
8.说出几种 vue 当中的指令和它的用法?#
答:v-model 双向数据绑定;
v-for 循环;
v-if v-show 显示与隐藏;
v-on 事件;v-once: 只绑定一次。
9.vue-loader 是什么?使用它的用途有哪些?#
答:vue 文件的一个加载器,将 template/js/style 转换成 js 模块。
用途:js 可以写 es6、style 样式可以 scss 或 less、template 可以加 jade 等
10.为什么使用 key?#
答:需要使用 key 来给每个节点做一个唯一标识,Diff 算法就可以正确的识别此节点。
作用主要是为了高效的更新虚拟 DOM。
11.axios 及安装?#
答:请求后台资源的模块。npm install axios --save 装好,
js 中使用 import 进来,然后. get 或. post。返回在. then 函数中如果成功,失败则是在. catch 函数
中。
12.v-modal 的使用。#
答:v-model 用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
v-bind 绑定一个 value 属性;
v-on 指令给当前元素绑定 input 事件。
13. 请说出 vue.cli 项目中 src 目录每个文件夹和文件的用法?#
答:assets 文件夹是放静态资源;components 是放组件;router 是定义路由相关的配置; app.vue 是
一个应用主组件;main.js 是入口文件。
14. 分别简述 computed 和 watch 的使用场景#
答:computed:
当一个属性受多个属性影响的时候就需要用到 computed
最典型的栗子: 购物车商品结算的时候
watch:
当一条数据影响多条数据的时候就需要用 watch
栗子:搜索数据
15.v-on 可以监听多个方法吗?#
答:可以,栗子:
16.$nextTick 的使用#
答:当你修改了 data 的值然后马上获取这个 dom 元素的值,是不能获取到更新后的值,
你需要使用 $nextTick 这个回调,让修改后的 data 值渲染更新到 dom 元素之后在获取,才能成功。
17.vue 组件中 data 为什么必须是一个函数?#
答:因为 JavaScript 的特性所导致,在 component 中,data 必须以函数的形式存在,不可以是对象。
组建中的 data 写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份
新的 data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混
乱。而单纯的写成对象形式,就是所有的组件实例共用了一个 data,这样改一个全都改了。
18. 渐进式框架的理解#
答:主张最少;可以根据不同的需求选择不同的层级;
19.Vue 中双向数据绑定是如何实现的?#
答:vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同
步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
核心:关于 VUE 双向数据绑定,其核心是 Object.defineProperty() 方法。
20. 单页面应用和多页面应用区别及优缺点#
答:单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的
html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片
段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于 pc 端。
多页面(MPA),就是指一个应用中有多个页面,页面跳转时是整页刷新
单页面的优点:
用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点 spa 对服务器压力较小;前后端分
离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。
单页面缺点:
不利于 seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的
前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。
21.v-if 和 v-for 的优先级#
答:当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个
v-for 循环中。所以,不推荐 v-if 和 v-for 同时使用。
如果 v-if 和 v-for 一起用的话,vue 中的的会自动提示 v-if 应该放到外层去。
22.assets 和 static 的区别#
答:相同点:assets 和 static 两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,
样式文件等都可以放在这两个文件下,这是相同点
不相同点:assets 中存放的静态资源文件在项目打包时,也就是运行 npm run build 时会将 assets 中
放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静
态资源文件最终也都会放置在 static 文件中跟着 index.html 一同上传至服务器。static 中放置的静态资
源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免
了压缩直接进行上传,在打包时会提高一定的效率,但是 static 中的资源文件由于没有进行压缩等操
作,所以文件的体积也就相对于 assets 中打包后的文件提交较大点。在服务器中就会占据更大的空间。
建议:将项目中 template 需要的样式文件 js 文件等都可以放置在 assets 中,走打包这一流程。减少体
积。而项目中引入的第三方的资源文件如 iconfoont.css 等文件可以放置在 static 中,因为这些引入的
第三方文件已经经过处理,我们不再需要处理,直接上传。
23.vue 常用的修饰符#
答:.stop:等同于 JavaScript 中的 event.stopPropagation(),防止事件冒泡;
.prevent:等同于 JavaScript 中的 event.preventDefault(),防止执行预设的行为(如果事件可取消,
则取消该事件,而不停止事件的进一步传播);
.capture:与事件冒泡的方向相反,事件捕获由外到内;
.self:只会触发自己范围内的事件,不包含子元素;
.once:只会触发一次。
24.vue 的两个核心点#
答:数据驱动、组件系统
数据驱动:ViewModel,保证数据和视图的一致性。
组件系统:应用类 UI 可以看作全部是由组件树构成的。
25.vue 和 jQuery 的区别#
答:jQuery 是使用选择器($)选取 DOM 对象,对其进行赋值、取值、事件绑定等操作,其实和原生
的 HTML 的区别只在于可以更方便的选取和操作 DOM 对象,而数据和界面是在一起的。比如需要获取
label 标签的内容:$("lable").val();, 它还是依赖 DOM 元素的值。
Vue 则是通过 Vue 对象将数据和 View 完全分离开来了。对数据进行操作不再需要引用相应的 DOM 对
象,可以说数据和 View 是分离的,他们通过 Vue 对象这个 vm 实现相互的绑定。这就是传说中的
MVVM。
26. 引进组件的步骤#
答: 在 template 中引入组件;
在 script 的第一行用 import 引入路径;
用 component 中写上组件名称。
27.delete 和 Vue.delete 删除数组的区别#
答:delete 只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。Vue.delete 直接
删除了数组 改变了数组的键值。
28.SPA 首屏加载慢如何解决#
答:安装动态懒加载所需插件;使用 CDN 资源。
29.Vue-router 跳转和 location.href 有什么区别#
答:使用 location.href='/url'来跳转,简单方便,但是刷新了页面;
使用 history.pushState('/url'),无刷新页面,静态跳转;
引进 router,然后使用 router.push('/url') 来跳转,使用了 diff 算法,实现了按需加载,减少了 dom
的消耗。
其实使用 router 跳转和使用 history.pushState() 没什么差别的,因为 vue-router 就是用了
history.pushState(),尤其是在 history 模式下。
30. vue slot#
答:简单来说,假如父组件需要在子组件内放一些 DOM,那么这些 DOM 是显示、不显示、在哪个地方
显示、如何显示,就是 slot 分发负责的活。
31. 你们 vue 项目是打包了一个 js 文件,一个 css 文件,还是有多个文件?#
答:根据 vue-cli 脚手架规范,一个 js 文件,一个 CSS 文件。
32.Vue 里面 router-link 在电脑上有用,在安卓上没反应怎么解决?#
答:Vue 路由在 Android 机上有问题,babel 问题,安装 babel polypill 插件解决。
33.Vue2 中注册在 router-link 上事件无效解决方法#
答: 使用 @click.native。原因:router-link 会阻止 click 事件,.native 指直接监听一个原生事件。
34.RouterLink 在 IE 和 Firefox 中不起作用(路由不跳转)的问题#
答: 方法一:只用 a 标签,不适用 button 标签;方法二:使用 button 标签和 Router.navigate 方法
35.axios 的特点有哪些#
答:从浏览器中创建 XMLHttpRequests;
node.js 创建 http 请求;
支持 Promise API;
拦截请求和响应;
转换请求数据和响应数据;
取消请求;
自动换成 json。
axios 中的发送字段的参数是 data 跟 params 两个,两者的区别在于 params 是跟请求地址一起发送
的,data 的作为一个请求体进行发送
params 一般适用于 get 请求,data 一般适用于 post put 请求。
36. 请说下封装 vue 组件的过程?#
答:1. 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。(os:思考 1 小时,码码
10 分钟,程序猿的准则。)
\2. 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
\3. 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
\4. 封装完毕了,直接调用即可
37.params 和 query 的区别#
答:用法:query 要用 path 来引入,params 要用 name 来引入,接收参数都是类似的,分别是
this.route.query.name和this.route.params.name。
url 地址显示:query 更加类似于我们 ajax 中 get 传参,params 则类似于 post,说的再简单一点,前
者在浏览器地址栏中显示参数,后者则不显示
注意点:query 刷新不会丢失 query 里面的数据
params 刷新 会 丢失 params 里面的数据。
38.vue 初始化页面闪动问题#
答:使用 vue 开发时,在 vue 初始化之前,由于 div 是不归 vue 管的,所以我们写的代码在还没有解析
的情况下会容易出现花屏现象,看到类似于 {{message}} 的字样,虽然一般情况下这个时间很短暂,但
是我们还是有必要让解决这个问题的。
首先:在 css 里加上 [v-cloak] {
display: none;
}。
如果没有彻底解决问题,则在根元素加上 style="display: none;" :style="{display:'block'}"
39.vue 更新数组时触发视图更新的方法#
答: push();pop();shift();unshift();splice(); sort();reverse()
40.vue 常用的 UI 组件库#
答:Mint UI,element,VUX
41. Vue的生命周期?#
beforeCreate 、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、
destroyed(创建、挂载、更新、卸载)
挂载中可以操作DOM,创建中不能操作DOM;常用挂载或者创建生命周期就行了
42.虚拟DOM和DIFF算法?#
将DOM抽象为虚拟DOM, 然后通过新旧虚拟DOM 这两个对象的差异(Diff算法),最终只把变化的部分重新
渲染,提高渲染效率的过程;
diff 是通过JS层面的计算,返回一个patch对象,即补丁对象,在通过特定的操作解析patch对象,完成
页面的重新渲染
43.vue2和vue3原理?#
1. vue2和vue3双向数据绑定原理发生了改变
vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 发布订阅模式
的方式来实现的。
vue3 中使用了 es6 的 ProxyAPI 对数据代理。
相比于vue2.x,使用proxy的优势如下
defineProperty只能监听某个属性,不能对全对象监听
可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化
2、默认进行懒观察(lazy observation)
在 2.x 版本里,不管数据多大,都会在一开始就为其创建观察者。当数据很大时,这可能会在页面载入
时造成明显的性能压力。3.x 版本,只会对「被用于渲染初始可见部分的数据」创建观察者,而且 3.x 的
观察者更高效。
3、更精准的变更通知
比例来说:2.x 版本中,使用 Vue.set 来给对象新增一个属性时,这个对象的所有 watcher 都会重新运
行;3.x 版本中,只有依赖那个属性的 watcher 才会重新运行。
4、vue3新加入了TypeScript以及PWA的支持
5、vue2和vue3组件发送改变
44.生命周期钩子的一些使用方法:#
1.beforecreate:可以在加个loading事件,在加载实例是触发
2.created:初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
3.mounted:挂载元素,获取到dom节点
4.updated:如果对数据统一处理,在这里写上相应函数
5.beforeDestroy:可以一个确认停止事件的确认框
6.nextTick:更新数据后立即操作dom
45.开发中常用的指令有哪些?#
v-model:一般用在表达输入,很轻松的实现表单控件和数据的双向绑定
v-html:更新元素的innerHTML
v-show与v-if:条件渲染,注意二者区别
v-on:click:可以简写为@click,@绑定一个事件。如果事件触发了,就可以指定事件的处理函数
v-for:基于源数据多次渲染元素或模板
v-bind:当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM语法
v-bind:title=”msg”简写:title="msg"
参考链接
https://zhuanlan.zhihu.com/p/92407628
https://blog.csdn.net/qq_37481512/article/details/94400698
https://www.jianshu.com/p/9489fdf7c145
本文来自博客园,作者:Tipsy(微醺),转载请注明原文链接:https://www.cnblogs.com/dj2016/articles/16866457.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示