网络
http五层网络
应用层(http),表示层, 会话层,传输层(tcp, udp),网络层,数据链路层, 物理层
http协议,https协议
- http协议:
- 超文本传输协议,是应用层协议。
- 请求和响应两个过程,客户端通过url地址发送请求到服务器,服务器收到请求后返回数据给客户端
- 请求包含请求头和请求体,请求头包含请求方法,版本协议,主机名,以及一些其他的属性,请求体一般带有
Content-Type
来描述请求体使用的格式 - 响应包含响应头和响应体,响应头一般包含版本协议,状态码,消息以及
Content-Type
,响应体就是返回的数据
- https协议
- HTTP下加入SSL层,是传输层协议
- https协议的主要作用是:建立一个信息安全通道,来确保数组的传输,确保网站的真实性。
- 区别
- http协议是无状态的,明文传输,不安全
- htttp基于tcp的可靠性传输
- http协议的端口为80, https端口是443
- https由SSL+HTTP协议构建的可进行加密传输,比http协议安全
请求方法
根据REST风格:
- get:获取
- post:新增
- put:更新
- patch:更新
- delete:删除
GET和POST区别
语义上或者从restful api角度上看你: get是从服务器获取资源, post是在服务器新建一个资源
实现上,或者浏览器端:
- get的数据参数会在url上可见, post请求不显示再url上
- get请求的数据能收藏为书签, 按后退按钮或者刷新无影响,
post请求到的数据不能收藏未书签, 按后退或刷新按钮, post会重新请求数据 - get与post比,安全性较差,但是两者皆不安全,可以使用HTTPS协议
- get对数据的请求长度是有限制的,post没有限制
状态码
- 200 OK:一切正常。你好,
我好,大家好。
- 301 Moved Permanently:永久性重定向, 请求的资源分配了新的url,使用更改的url
- 302 Found: 临时性重定向, 请求的资源分配了新的uel, 本次使用新的url, 但是之后可能还会更改
- 304 Not Modified:get请求被允许,但是文档内容并没有改变,协商缓存。
你的请求我收到了,你要的东西跟之前是一样的,没有任何的变化,所以我就不给你结果了,你自己就用以前的吧。啥?你没有缓存以前的内容,关我啥事
- 400 Bad Request:语义有误,当前请求无法被服务器理解。
你给我发的是个啥啊,我听都听不懂
- 403 Forbidden:服务器拒绝执行。没有访问权限
你的请求我已收到,但是我就是不给你东西
- 404 Not Found:资源不存在。
你的请求我收到了,但我没有你要的东西
- 500 Internal Server Error:服务器内部错误。
你的请求我已收到,但这道题我不会,解不出来,先睡了
强缓存,协商缓存
因为服务器上的资源不是一直固定不变的,大多数情况下它会更新,这个时候如果我们还访问本地缓存,那么对用户来说,那就相当于资源没有更新,用户看到的还是旧的资源;所以我们希望服务器上的资源更新了浏览器就请求新的资源,没有更新就使用本地的缓存,以最大程度的减少因网络请求而产生的资源浪费。
- 缓存分为两种:强缓存和协商缓存,根据响应的header内容来决定。
- 强缓存相关字段有expires,cache-control。如果cache-control与expires同时存在的话,cache-control的优先级高于expires。
- 强缓存中,普通刷新会忽略它,但不会清除它,需要强制刷新。
- 普通刷新会启用弱缓存,忽略强缓存。只有在地址栏或收藏夹输入网址、通过链接引用资源等情况下,浏览器才会启用强缓存,
- 协商缓存相关字段有Last-Modified/If-Modified-Since,Etag/If-None-Match
常见的http请求头
- Host:服务器域名和端口号,默认80可以省略
- Accept,接受的响应类型,Content-Types
- Accept-Charset:可接受的字符集,utf-8
- Accept-Encoding:可接受的响应内容的编码方式。utf-8
- Accept-Language:可接受的响应内容语言列表。
- Cache-Control:用来指定当前的请求/回复中的,是否使用缓存机制。默认为private。
常见的值为max-age, s为单位, 在文档被访问后的存活时间,
如果这个文档在存活期间再次被请求访问,则不会向服务器再此发送一次请求
如果值为 no-cache,那么每次都会访问服务器。 - cookie: getCookie, setCookie, 用于存放一些信息,http是无状态的,cookie用来记录。
- user-agent: 浏览器内核和版本号
tcp三次握手
- 客户端主动去链接服务端, 发送SYN
- 服务端即受到SYN后, 也会发送一个SYN和一个应答给客户
- 客户接收到新的SYN和应答后,也回应应答并表示收到了 然后两边就可以数据发送了
TCP和UDP的区别
- TCP面向连接,UDP是无连接的,即发送数据前不需要先建立链接。
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。 并且因为tcp可靠,面向连接,不会丢失数据因此适合大数据量的交换。
- 每一条TCP连接只能是点到点,UDP支持一对一、一对多、多对多
- TCP的首部较大为20字节,而UDP只有8字节。
浏览器输入url发生了什么
- 查询IP地址
- 浏览器解析出url中的域名
- 查询浏览器DNS缓存
- 如果不存在浏览器缓存中, 看本机host, 进查找本地host文件有无对应的ip地址
- host中没有, 就查找本地DNS服务器有无缓存
- 本地DNS没有缓存, 想跟服务器递归查找
- 递归查找从顶级域名开始(.com), 最终获得ip地址
- http请求,tcp建立连接
- http协议建立再tcp协议之上,http请求之前,先tcp建立连接,建立客户端到服务器的通道,称作为三次握手
- tcp链接完成后,进行http请求,请求方式常见的有get和post
- http请求, 包括请求头和请求体,请求头为请求方式, url , 协议版本,请求体为传递个后台的参数
- 服务器接收到http请求后, 开始工作, 负载平和,跨域等
- 文件处理完毕后, 生成响应数据包, 响应包含响应头, 响应体, 响应体就是请求的文件
- 经过网络传输, 文件被下载到本地客户端,客户端开始加载,进行html渲染(contentType:text/html)
- html渲染
- 由上到下渲染dom树
- 遇到css文件, 发起http请求
- 第二次http请求, http1.1 中的 connection:keep-alive, 不会终端tcp链接,可以复用
- http连接是无状态的, 客户端和服务器端需要重新发送请求-响应
- 在请求css过程中, 解析器继续解析html,
- 遇到了script标签后,可能会改变dom树, 停止解析html, 遇到js阻塞, js发起http请求
- css树生成后与dom树生成渲染树
- 渲染树生成后,绘制渲染树中的节点属性(宽度,大小,位置)
- js文件执行后改变dom树, 渲染树会被改变的dom再次被渲染
- img标签会再次发送http请求,
- dom树遇到html结束标签,渲染结束
Http2.0
- 内容安全,是基于HTTPs的
- 二进制格式,采用二进制格式编码
- 多路复用,所有的请求都是通过一个TCP 连接并发完成,一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。(connection:Keep-alive)
websocket
- HTML5 网络通信协议,解决了http通信只能由客户端发送到服务端,
- 没有同源限制, 客户端可以与任意服务器通信。
- 建立在 TCP 协议之上,服务器端的实现比较容易。
- 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器
cookie和session的区别,localstorage和sessionstorage的区别
- cookie
- cookie是用于客户端存储一般用来存放不敏感信息
- cookie不能存储超过4k
- 默认关闭浏览器后失效
- 携带在http请求头中
- session
- session用于服务器信息存储,一般用来存储用户信息
- session会在一定时间内保存在服务器中,访问量增多,会影响性能
- 仅在当前网页会话下有小,关闭页面或浏览器会失效
- localstorage
- 除非手动删除,否则永远保存
- 可以保存5M的信息
- sessionstorage
- 仅在当前网页会话下有小,关闭页面或浏览器会失效
- 可以保存5M的信息
HTML
BOM,DOM
什么是Bom? Bom是浏览器对象。有哪些常用的Bom属性呢?
(1)location对象
location.href-- 返回或设置当前文档的URL
location.search – 返回URL中的查询字符串部分。例如 http://www.dreamdu.com/dreamdu.php?id=5&name=dreamdu 返回包括(?)后面的内容?id=5&name=dreamdu
location.hash – 返回URL#后面的内容,如果没有#,返回空
location.host – 返回URL中的域名部分,例如www.dreamdu.com
location.hostname – 返回URL中的主域名部分,例如dreamdu.com
location.pathname – 返回URL的域名后的部分。例如 http://www.dreamdu.com/xhtml/ 返回/xhtml/
location.port – 返回URL中的端口部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回8080
location.protocol – 返回URL中的协议部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回(//)前面的内容http:
location.assign – 设置当前文档的URL
location.replace() – 设置当前文档的URL,并且在history对象的地址列表中移除这个URL location.replace(url);
location.reload() – 重载当前页面
(2)history对象
history.go() – 前进或后退指定的页面数 history.go(num);
history.back() – 后退一页
history.forward() – 前进一页
(3)Navigator对象
navigator.userAgent – 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串)
navigator.cookieEnabled – 返回浏览器是否支持(启用)cookie
viewport响应式移动端布局,meta标签
https://github.com/forthealllight/blog/issues/13
<meta id="viewport" name="viewport"
content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;">
meta
是元数据,不会显示在页面上,但对于机器是可读的,告诉浏览器如何解析这个页面,可以添加服务器发送到浏览器的http头部内容
name 和content属性, 描述页面的内容,搜索引擎会利用name和content来找到页面
content属性:必须于name或http-equiv一起出现(key value)
http-equiv: 发送请求时,浏览器中头部包含的内容(5s后重新请求)
name:可以解决一些兼容问题,name=‘render’ content= ‘webkit’
charest: utf-8 编码
标签语义化
HTML5语义化标签是指正确的标签包含了正确的内容,结构良好,便于阅读,比如nav表示导航条,类似的还有article、header、footer等等标签。
src 和href区别
(1)请求资源类型不同:
href是超文本引用的简写,用来为当前元素和文档之间建立连接,常用的是link、a标签。
src会将指向的资源下载并引用到当前文档中,常用的标签有script,img,iframe标签。
(2)作用的结果不同:
href是为当前文档和引用资源建立联系;
而src是替换当前的元素。
(3)浏览器的解析方式不同
herf引用的资源,浏览器会将其识别为CSS文档,并行下载资源并且不会停止对当前文档的处理。
当浏览器解析到src时,会暂停其他资源的下载和处理,直接将该资源下载,编译,执行完毕,图片和框架也是如此,类似于将所指资源应用到当前内容。
HTML5新增的元素
CSS
画三角形
.triangle{
width: 0px; /*设置宽高为0,所以div的内容为空,从才能形成三角形尖角*/
height: 0px;
border-bottom: 200px solid #00a3af;
border-left: 200px solid transparent; /*transparent 表示透明*/
border-right: 200px solid transparent;
}
盒模型
https://zhuanlan.zhihu.com/p/110617108
BFC(外边距问题)
https://zhuanlan.zhihu.com/p/110617108
居中
- 已知宽度:margin:0 auto
- 父元素:position:relative,子元素,position:absolute,top,left50%,translate-50%(宽度未知)
- 父元素flex,vertical-align: middle;//使子元素垂直居中(宽度未知)
text-align: center;//使子元素水平居中
行元素,块元素
块元素: 独占一行,可以设置宽高外边距, div h ul li dl form table
行元素: 可以和其他行元素共占一行, span b a i
行内块元素: img input
flex布局
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
圣杯布局,content:display flex
opacity和rgba
有opacity属性的所有后代元素都会继承 opacity 属性,而RGBA后代元素不会继承不透明属性
重绘和重排
浏览器窗口大小发生改变,重排一定导致重绘,重绘不一定导致重排,
- 重绘
页面中的元素产生变化但不回影响元素再文档中的位置(color, visibility), 浏览器会将新样式赋予元素并重新绘制, 成为重绘 - 回流
页面中的元素的变化会影响再文档中的位置, 大小,结构的变化,浏览器重新渲染部分或全部文档的过程称为回流。 - 性能影响
- 避免
- CSS
避免使用 table 布局。
尽可能在 DOM 树的最末端改变 class。
避免设置多层内联样式。
将动画效果应用到 position 属性为 absolute 或 fixed 的元素上。
避免使用 CSS 表达式(例如:calc())。 - Javascript
避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。
也可以先为元素设置 display: none,操作结束后再把它显示出来。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。
- CSS
position属性
相对定位relative:
如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直或水平位置,让这个元素“相对于”它的起点进行移动。 在使用相对定位时,无论是否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。
绝对定位absolute:
绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于。 absolute 定位使元素的位置与文档流无关,因此不占据空间。 absolute 定位的元素和其他元素重叠
为什么?怎么浮动清除
子元素的浮动导致了父元素高度的塌陷。
导致背景不能显示,如果对父级设置了背景属性,导致父级不能撑开,会影响到背景图片不能正常打开。
边框不能撑开,由于子级使用了浮动效果,并且已经产生了浮动,父级不能撑开,所以影响边框不会随着内容的变化而变化。
- BFC:给父元素添加overflow:hidden
- 多加一个div,设置clear:both
JavaScript
this指向的理解
this是指隐式全局上下文,
this实际上在函数被调用时发生绑定,它指向什么完全取决于函数在那里被调用,
调用函数的时候,会有一个执行上下文,记录函数在那里被调用,调用的方式,传入信息等,this就是这个记录中的属性,在函数执行的时候被用到
实现继承的方法
https://blog.youkuaiyun.com/Hunt_bo/article/details/108073473
数据类型
- 基本类型
string,number,boolean,null,undefined,symbol - 引用类型
function,array,object
判断类型
typeof NaN = “number”
typeof和instanceof
instanceof是用来判断一个对象在其原型链中是否存在一个构造函数的prototype属性
a instanceof b:判断a是否为b的实例,可以用于继承关系中
undefined和null
[] == [] 和 [] == ![]和{} == !{}
https://blog.youkuaiyun.com/magic_xiang/article/details/83686224
如果两个操作数都是对象,则比较它们是不是同一个对象。如果指向同一个对象,则相等操作符返回 true
[] == ! [] -> [] == false -> Number([])== Number(false) -> ‘’ == 0 -> 0 == 0 -> true
{} == !{} -> {} == false -> Number({}) == Number(false) -> NaN == 0
相等和不相等——先转换再比较 (==)
全等和不全等——仅比较而不转换 (===)
Object.is 和 == 和===
- == 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的结果会将 “” == false 判断为 true), 而 Object.is不会强制转换两边的值。
- +0和-0不相等
- === 运算符 (也包括 == 运算符) 将数字 -0 和 +0 视为相等 ,而将Number.NaN 与NaN视为不相等.
- == 和 ===区别
==:比较内容。 会先做类型转换
===: 比较类型和内容,
普通函数和箭头函数的区别
- this
- 箭头函数this指向上下文的this,普通函数指向的是调用它的对象
- 因此箭头函数内使用call,apply,bind不好使
- 箭头函数中不能使用构造函数
- 箭头函数不绑定arguments
通常在var self= this的时候用箭头函数可以做个很好的替代
call apply bind
call(递给函数的参数必须列举出来)和apply(参数数组。)都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加
上下文和变量提升
变量提升优先级:函数声明大于变量声明
let声明的变量不会被提升,而且是块级作用域,存在暂时性死区
https://blog.youkuaiyun.com/zebghfv/article/details/118251097
函数节流和抖动
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖靠清除定时器操作,只是在最后一次事件后或第一次才触发一次函数。
https://blog.youkuaiyun.com/qq_37918241/article/details/99656110
事件循环机制
js是单线程,js执行环境(全局上下文),同步就先执行同步的,遇到定时任务,事件监听,网络线程,要先存到事件队列中,promise产生的回调放入微队列,计时器等放入宏队列,当执行环境中没有任务执行,先去微队列中取出执行,然后执行后队列中的任务,知道全局上下文执行完毕
async await之后的函数相当于promise.then(),是为队列中的,之前的是立即执行函数
new Promise是立即执行函数,promise.then是为队列中的异步
console.log(1)
async function async1() {
await async2()
console.log(2)
}
async function async2() {
console.log(3)
}
async1()
setTimeout(function () {
console.log(4)
}, 0)
new Promise(resolve => {
console.log(5)
resolve()
})
.then(function () {
console.log(6)
})
.then(function () {
console.log(7)
})
console.log(8)
</script>
<!-- 1 3 5 8 2 6 7 4
宏 4
微 2 6 7 -->
事件流,事件委托,冒泡,捕获,以及如何阻止
https://www.cnblogs.com/soyxiaobi/p/9498357.html
闭包
函数外部对内部的引用,
ES6中的迭代器原理就用了闭包
迭代器创建函数返回了next方法,next方法返回了一个对象
外部对next方法的和对象的引用就是一个闭包.
深拷贝浅拷贝
https://www.jianshu.com/p/1c142ec2ca45
原型链
每个实例对象(object)都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null
function doSomething(){}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
console.log( doSomeInstancing );
doSomeInstancing ._proto = doSomething.prototype
function doSomething(){}
doSomething.prototype.foo = "bar";
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value";
console.log("doSomeInstancing.prop: " + doSomeInstancing.prop);
console.log("doSomeInstancing.foo: " + doSomeInstancing.foo);
console.log("doSomething.prop: " + doSomething.prop);
console.log("doSomething.foo: " + doSomething.foo);
console.log("doSomething.prototype.prop: " + doSomething.prototype.prop);
console.log("doSomething.prototype.foo: " + doSomething.prototype.foo);
解决异步回调地狱
- 原先的解决办法
- 回调函数: 但是容易出现回调地狱,像Ajax
- 事件监听: 执行顺序去决议某个时间是否发生,
缺点: 异步之间的联系, 某个异步要等待多个异步的操作结果,代码会复杂
- ES6的解决
- Promise
- async await
- Generator yield
js的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的区别
ES6
new操作符
https://zhuanlan.zhihu.com/p/158640941
function create(Con,...args){
//1、创建一个空的对象
let obj = {}; // let obj = Object.create({});
//2、将空对象的原型prototype指向构造函数的原型
Object.setPrototypeOf(obj,Con.prototype); // obj.__proto__ = Con.prototype
//3、改变构造函数的上下文(this),并将剩余的参数传入
let result = Con.apply(obj,args);
//4、在构造函数有返回值的情况进行判断
return result instanceof Object?result:obj;
}
let const var
ES6新增数据类型
Set Map Symbol
Map Object
key唯一,链式调用,用for…of遍历
Set Array
唯一性, set.size, 只能for of遍历取值, set.add set.has,数组去重
对数组和Set进行结构展开运算符是调用了[Symbol.iterrator]方法
ES6新增数组方法
- 将参数转换成数组: Array.form(), Array.of()
- 拉平多维数组, flat
- includes:数组是否包含给定的值
- fill:填充数组
对象新增方法
https://es6.ruanyifeng.com/#docs/object-methods
Object.is
同值相等
NaN等于本身, +0 不等于-0
Object.assign
可枚举对象的合并, 浅拷贝
Object.keys values entries
for of, for in
- for of
[Symbol.iterator], value
for…of 循环可以与break、continue 和 return 配合使用 - for in: key
- find方法,用于找出第一个符合条件的数组成员。
简单的实现一个promise.all
function promiseAll(promises){
return new Promise((resolve, reject) => {
if(!Array.isArray(promises)) {
return reject(new TypeError('argument must be array'))
}
const length = promises.length;
let resolveArr = [];
let num = 0;
for(let i = 0; i < length; i ++) {
(function(i) {
Promise.resolve(promises[i]).then(function(v) {
num ++;
resolveArr[i] = v;
if ( resolveArr[i] === promises ) {
return resolve(resolveArr)
}
}, function(err) {
return reject(err)
})
})(i)
}
})
}
const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]
promiseAll(promises).then(v =>{
console.log('all', v)
})
TS
数据类型
- 基础类型
boolean,number,string,array,null,undefined,object,never, Any, Void
- 元组:Tuple, 规定了数组每一项的类型和数量,月结元素可以用联合类型代替
- 枚举:枚举没有赋值默认是从0开始的依次递增的排序顺序
- 高级类型
- 联合类型(只能访问共同成员, 类型合并)
let a: string | number; - 交叉类型
多种类型的集合
interface People {
age: number,
height: number
}
interface Man{
sex: string
}
const lilei = (man: People & Man) => {
console.log(man.age)
console.log(man.height)
console.log(man.sex)
}
lilei({age: 18,height: 180,sex: 'male'});
类型断言: as
泛型
- any类型的话会导致丢失信息,传入参数和返回参数类型不一致
- 泛型会有一些规定
interface
开发中有一些很长的参数,并且每个参数都是有固定类型或者规定的,就可以用接口单独封装起来.
- 对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”
- 接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。
类
- super,调用基类的constructor
- private:只有类内部
- protexcted:派生类也可以
- 静态属性,必须通过类.调用
- 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。(abstract)
封装
解决带啊吗重复问题
封装成一个类或接口
共同的方法,consturctoe函数,this指向
OOP(面向对象)
Vue
单向数据流和双向绑定
https://www.cnblogs.com/smilexuezi/p/13870165.html
组件间通信
- 父子组件
- prop: 父组件向子组件传递数据,子组件使用prop接受,单向数据流的形式
- event:子组件向父组件传递数据,子组件触发事件,通过
$emit
向父组件传数据,父组件通过@事件名
获取到值 - style,class / attribute(this.$attrs 没有任何声明prop属性,) / @clcik.native 在父组件中的子组件渲染的时候添加,会渲染的子组件的根节点上
- sync: 双向数据绑定,vue3和v-model进行了合并处理,v-model只能针对一个数据进行双向数据绑定
<input :value=‘loginId’ @input=‘$event.target.value’>
<Numbers :num1=‘n1’ :num2=‘n2’ @unpdate:num1=‘n1 = $event’ @unpdate:num2=‘n2 = $event’>
sync修饰符没有限制, 作为一个编译时的语法糖存在,它会被扩展为一个自动更新父组件属性的v-on监听器。带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)
- 跨组件(兄弟,祖孙等)
- Provide Inject: 上层组件通过provide提供数据,下层组件通过inject接受
- router:
<router-link>
改变<touter-view>
渲染, route, this.$route.params, hash route 和 history route - vuex:状态管理模式,多个组件共享状态时,保持单向数据流,适用与大型单页应用
通过mutation(){increment(){}}, this.$store.commit('increment')
来改变store.state中数据, 同步函数。
Actions
Action 提交的是 mutation,而不是直接变更状态。异步操作。传的参数是上下文
获取多个状态时,在计算属性中使用...mapState()
派生状态被多个组件共享时,Getter, ...mapGetters
- store模式,中小型应用,其实就是一个js模块。
- eventbus:事件总线,其实用的就是 --观察者模式–, 组件通知事件总线发生了某件事,事件总线通知其他监听该事件的所有组件。
===================================主要是prop和event,因为其他的可能会破坏单向数据流、
虚拟DOM
在vue
中,渲染视图会调用render
函数,这种渲染不仅发生在组件创建时,同时发生在视图依赖的数据更新时。如果在渲染时,直接使用真实DOM
,由于真实DOM
的创建、更新、插入等操作会带来大量的性能损耗,从而就会极大的降低渲染效率。
在一个组件实例首次被渲染时,它先生成虚拟dom树,然后根据虚拟dom树创建真实dom,并把真实dom挂载到页面中合适的位置,此时,每个虚拟dom便会对应一个真实的dom(elm
)。最小量更新
编译的过程分两步:
- 将模板字符串转换成为
AST
- 将
AST
转换为render
函数
数据响应式原理
- 首先原始对象通过
Object.defineProperty
变成带有getter和setter的响应式对象。
这件事发生在beforeCreate
之后,created
之前。
遍历只能遍历当前对象的属性,无法监测将来动态对象的改变,因此vue
提供了$set
和$delete
两个实例方法,让开发者通过这两个实例方法对已有响应式对象添加或删除属性。不要随便用set,delet,因为有对象的依赖,新增属性后还会出发渲染reder函数
遍历数组,vue
会更改它的隐式原型,之所以这样做,是因为vue需要监听那些可能改变数组内容的方法(pop, push, reverse, sort, splice, unshift, shift
) - 当渲染执行
render
函数的时候, 把函数交给watcher
对象去执行,wathcer会有一个全局变量去执行,被getter中的dep.depend()
记录依赖。 - 当触发某些事件改变数据的时候,会由
setter
中的dep.notify()
派发更新,通知watcher,交给调度器,将watcher添加到nextTick
微队列中。 - 异步执行watcher,运行函数,重新手机依赖
diff算法
- 当组件创建和更新时,vue会执行watcher中的_update函数,该函数中使用_render函数生成虚拟dom树,将新旧虚拟dom树进行比较,最终更新到真实的dom上
- 对比差异的过程通过patch函数完成
- 对比过程中通过同层比较,深度遍历
- 通过判断两个虚拟节点的标签和key是否相同来比较的
- 首先对比根节点,如果相同的话,让新的虚拟dom上的elm属性等于旧的虚拟dom的elm。 不同的话,递归新节点创建真实dom。
- 然后对比子节点,新旧两个子节点都有两个指针分别只想首位。
- 首指针相同,挂载真实dom到新节点,并更新属性,首指针++
- 首指针不同,就去比较尾指针,尾指针相同,挂载真实dom到新节点,并更新属性, 尾指针–
- 首指针不同,尾指针不同,就比较尾指针和首指针指向的虚拟节点,相同的话复用真实dom,更新属性,并且将真实dom位置提前
- 尾指针和首指针指向的虚拟节点不同,就查找首指针指向的新节点是否在就节点中,如果存在,复用真实dom,更新属性和位置
- 依次递归。
对开发的影响
- 循环数组,加key值
如果不加key的话,需要更改子节点内容,加了可以之后,只需要移动真实dom的位置(数组顺序和头部插入举例)
生命周期
- 生命周期钩子函数有: beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestory, destoryed
- 在beforeCreate之前会创建一些实例
- 运行beforeCreate钩子函数
- 创建可响应对象,处理属性,methods,computed,把这些挂载到实例中。
- 运行created钩子函数,这个时候可以获取到数据,以及方法的使用,但是哦不能获取真实dom,进行异步处理。
- 生成render函数或者编译模板,创建虚拟dom,执行_update函数,生成真实dom
- 运行mounted钩子函数,这个时候可以获取到dom,并对dom进行操作
- 当数据变化时,会执行watcher中的依赖收集,watcher会被派发到nextTick微队列中,避免多个依赖被同时改变后多次执行
- 运行 beforeUpdate钩子函数
- 执行_update函数,触发_patch,函数新旧虚拟dom数比较
- 新组建创建进入实例化,销毁用destroy删除组件,触发beforeDestory函数,
- 递归调用子组件destroy方法,触发destoryed函数
- 运行updated钩子函数
computed
- 在使用时,computed当做属性使用,而methods则当做方法调用
- computed可以具有getter和setter,因此可以赋值,而methods不行
- computed无法接收多个参数,而methods可以
- computed具有缓存,而methods没有
vue对methods的处理比较简单,只需要遍历methods配置中的每个属性,将其对应的函数使用bind绑定当前组件实例后复制其引用到组件实例中即可
而vue对computed的处理会稍微复杂一些。
当组件实例触发生命周期函数
beforeCreate
后,它会做一系列事情,其中就包括对computed的处理它会遍历computed配置中的所有属性,为每一个属性创建一个Watcher对象,并传入一个函数,该函数的本质其实就是computed配置中的getter,这样一来,getter运行过程中就会收集依赖
但是和渲染函数不同,为计算属性创建的Watcher不会立即执行,因为要考虑到该计算属性是否会被渲染函数使用,如果没有使用,就不会得到执行。因此,在创建Watcher的时候,它使用了lazy配置,lazy配置可以让Watcher不会立即执行。
收到
lazy
的影响,Watcher内部会保存两个关键属性来实现缓存,一个是value
,一个是dirty
value
属性用于保存Watcher运行的结果,受lazy
的影响,该值在最开始是undefined
dirty
属性用于指示当前的value
是否已经过时了,即是否为脏值,受lazy
的影响,该值在最开始是true
Watcher创建好后,vue会使用代理模式,将计算属性挂载到组件实例中
当读取计算属性时,vue检查其对应的Watcher是否是脏值,如果是,则运行函数,计算依赖,并得到对应的值,保存在Watcher的value中,然后设置dirty为false,然后返回。
如果dirty为false,则直接返回watcher的value
巧妙的是,在依赖收集时,被依赖的数据不仅会收集到计算属性的Watcher,还会收集到组件的Watcher
当计算属性的依赖变化时,会先触发计算属性的Watcher执行,此时,它只需设置
dirty
为true即可,不做任何处理。由于依赖同时会收集到组件的Watcher,因此组件会重新渲染,而重新渲染时又读取到了计算属性,由于计算属性目前已为dirty,因此会重新运行getter进行运算
而对于计算属性的setter,则极其简单,当设置计算属性时,直接运行setter即可
优化
vue性能优化
- 使用key值
在进行diff算法的过程中,有了key值可以减少对节点的修改,新增和删除,主要用于循环列表 - 使用冻结对象
冻结对象:Object.freeze(obj)
对于列表多别躲,深度大,这样就不用被变成响应式数据 - 使用函数式组件
functional: true,
, 没有响应式,没有组件实例(this上下文) - 使用计算属性
用多次同一个数据,并且会对这个数据进行修改,有缓存,就可以用计算属性 - 使用v-show代替v-if
对于频发切换显示状态,包含大量子节点dom元素,使用v-show保持了dom元素的稳定行 - 分帧,分片延迟加载
解决空白页、 - keep-alive
保存组件实例(data, computed, $el), 减少dom创建和缓存了组件实例中的内容
但是没用调用destroyed生命周期钩子函数,所以导致内存占用
include exclude name max
keep-alive的所有被缓存的子组件缓存之后不会运行其他生命周期函数,所以他们具有activated deactivated
两个周期函数,
分别在组件激活和失活时触发。
原理:
-
有一个keys数组,存放组件的key,一个cache对象,key为keys,value为组件对应的vnode。
```javascript // keep-alive 内部的声明周期函数 created () { this.cache = Object.create(null) this.keys = [] } ```
-
如果组件中的key在cache中,那么就将组件的实例指向cache中key对应的实例, 从keys中删除key,并将key插入到keys的末尾,保证最近使用的在数组最后
-
不在缓存对象中,那么就进行缓存,如果keys长度超过max,就删除第一个key对应的缓存
vuex
- state
- getters:需要将state中的数据派生出一些状态,类似于computers
通过 this.$store.getters.doneTodosCount 访问 - Mutation:更改state中的状态,通过store.commit(‘increment’),执行mutation中的方法
- Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters
store.dispatch触发
可以和ascyn,promise使用
vue重置css
https://www.freesion.com/article/1661486992/
vue路由守卫
vue3
重大变化
1. 没有Vue构造函数,使用的时createApp创建,返回Vue实例
2. this为proxy,指向的是一个代理,代理组件实例
3. compositionApi
- Vue2的optionApi,将属性(data,methods, computed)等进行配置
这样会导致同一个功能的处理逻辑分散在各个地方 - compositionApi
import {ref} from 'vue' setup(props, ctx){// 所有属性, 上下文 //在所有生命周期钩子函数之前调用 //this -> undefined let count = ref(0); // 具有响应式 const increase = () => { count.value ++; }; const handleCheck = () => { ctx.emit('update:modelValue', props.checked) //触发事件的事件名 } return{ count, increase //放在了组件实例中 } } ```
template
中可以有多个根节点- 效率有很大的的提升
- 静态节点和属性提升到render函数上面
- 大量连续静态节点预字符串,将静态内容编译为一个普通字符串节点
- 对比新旧树的时候,有一个标记时动态节点还是静态节点。 - v-if优先级高于v-for
vue2中v-for高于v-if,写在一起会影响性能,因为每次修改之后要进行循环一次中判断,所以卸载计算属性中筛选
vue3响应式数据原理
vue3中使用proxy完成数据相应
proxy效率比Object.defineProperty快,而且可以对属性进行删除和增加,索引访问等
Angular
模块化
Webpack
对webpack的理解
- 构建工具,主要用于构建vue,react前端框架的构建,编译
将开发的代码进行构建,运行构建后的代码,这样就会提高效率,兼容 - 基于模块化的打包工具,将开发使得所有资源文件视为模块,
通过开发时态的入口文件为起点,分析依赖,压缩合并成为一个为文件。
打包的过程时 基于node环境运行的, 通过模块化的导入语句进行依赖分析
webpack构建流程,编译过程?
- 初始化:将在命令行中输入的cli参数,配置文件(src/index.js),以及默认配置(webpack.config.js中的对象)进行融合,形成一个配置对象.
- 编译:
- chunk: 一个由入口文件开始引出的多个模块依赖的组合块,可以有多个chunk,有name和id,开发环境name和id相同,生产环境id是一个从0开始的数字。
- 构建所有依赖模块生成一个或多个chunk:
- 通过入口文件找到模块文件,通过模块id(路径)检查是否已经记录过,没有记录,读取文件内容。
- 读取文件内容后,如果当前模块匹配到了Loader规则,那么处理对应的loader规则。
- 处理后的代码内容进行AST抽象语法树进行树形结构遍历。找到所有的依赖。
- 将依赖的完整相对路径记录到dependences数组中
- 将读出来的字符串内容替换以来函数
- 保存转换后的模块代码记录到chunk中
- 递归dependences数组,重复步骤。
- 产生资源列表(chunk assets)
- 上一步中会生成一个或多个包含由模块id和模块转换后的代码组成的模块列表的chunk
- webpack会根据配置为chunk生成一个资源列表(bundle)。既生成到最终文件的文件名(./dist/mian.js)和文件内容(一个模板,字符串内容放到eval中)
- 将多个chunk assets 合并到一起,产生一个总的hash
- 输出:webpack利用node的fs模块,根据编译产生的总的hash生成相应的文件
hash: 在输出的时候配置名字带有 总的资源hash,用于解决缓存
常见的Loader
- css-loader: 将css代码转换为js,将css代码作为字符串导出(有一个toString方法)
- style-loader: 把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。(避免同一个样式重复导入, 一定要与css-loader配合使用)
- file-loader: 生成依赖的文件到输出目录,然后将模块文件设置为:导出一个路径,通过url进行引用(大文件)
- url-loader: 将文件转换成base64格式的字符串(小文件)
- image-loader:加载并且压缩图片文件
mini-css-extract-plugin: 抽离css文件,1个plugin,1个loader
常见的plugin
- mini-css-extract-plugin: 抽离css
- commons-chunk-plugin:提取公共代码
- HotModuleReplacementPlugin: 热更新
- TerserPlugin: 压缩js
Loader和Plugin的不同
-
Loader
- 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
- 在module.rules中配置,也就是说他作为模块的解析规则而存在。
-
Plugin
- 译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
- 在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。
编写Loader和Plugin的思路
- Loader
webpack中一切资源为模块,但是只能解析js,所以loader可以解析其他文件。
是用CommonJS,因为是在打包过程中的,mosule.exports=function(sourcecode)(retiurn '')
loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。module.exports = { module: { rules: [ //使用规则 { test: /\.js$/,//正则表达式,匹配需要loader的模块路径 use: ["./loaders/loader1?changeVar='var'"]//使用哪些loaderloader: , //loader路径(没有写在node_modules中,所以要写全路径) }, { test: /\.js$/,//正则表达式,匹配需要loader的模块路径 use: ["./loaders/loader1?changeVar='var','loader2'"]//使用哪些loaderloader: , //loader路径(没有写在node_modules中,所以要写全路径) } ] } }
loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。 - Plugin
发者可以引入它们自己的行为到 webpack 构建流程中。扩展webpack功能,可以触发事件。
本质是一个带有apply方法的对象(构造函数)。
compiler对象实在初始化阶段构建的,并在整个webpack打包期间只有一个compiler对象。module.exports = class myPlugin { apply(compiler){ complier.hooks.事件名称.事件类型(name, (compilation) => {}) } } index.js if(module.hot){ module.hot.accept() //socket }
后续完成打包工作的是compiler对象内部创建的compilation。
配置了watcher: true
中i后,修改打包模块,不会重新执行apply方法,而是注册事件
注册钩子函数:hooks
webpack-dev-server
```javascript
module.exports = {
module:{
},
devServer: {
port: 8000,
open: true,
proxy: {
'/api':{
target: 'http://localhost:8080', //请求地址包含/api那么代理请求地址为后面的地址(跨域问题)
changeOrigin: true //请求成功后却报404,是因为有些服务器需要请求头Host信息, 更改请求头中的host和origin
}
}
}
}
```
性能优化
-
构建性能(webpack)
- 减少模块解析(抽象语法树分析,以来分析,模块语法替换), 没有依赖关系,或者一些已经打包好的第三方库不需要模块解析
module.npParse: /jquery/
- 热更新
使用web-dev-server中的watch时,会在代码变动重新打包之后浏览器刷新,重新请求所有资源。
使用热更新之后重新打包之后,浏览器只请求改动的资源。
样式热更新需要使用style-loader,因为是在运行期间,mini-css-extract-plugin是在构建期间受鞥成文件,因此对热替换是无效的
- 减少模块解析(抽象语法树分析,以来分析,模块语法替换), 没有依赖关系,或者一些已经打包好的第三方库不需要模块解析
-
传输性能(webpack)
打包的js体积尽可能少,把变动少的代码合并到单独的文件中。- 分包:提取公共chunk, 减少公共代码,减少体积,把一个整体的代码分布到不同的打包文件中
多个chunk引入了公共模块module.exports = { optimization: { splitChunks: { chunks: 'all' } } }
- 代码压缩:一个模块代码太大,单模块体积优化。通过缩短变量名等。移出无效代码
module.exports = { optimization: { splitChunks: { chunks: 'all' }, minimizer: [ // 压缩时使用得到插件 new TerserPlugin(); ] } }
- tree-shaking, 单模块体积优化,移出模块之间无效代码
- 分包:提取公共chunk, 减少公共代码,减少体积,把一个整体的代码分布到不同的打包文件中
热更新
```javascript
module.exports= {
devServer: {
hot: true // 开启
},
plugin: [
new webpack.HotModuleReplacementPlugin() // 可选,webpack4之后不用写了
]
}
```
Nodejs
特性,优缺点
- 单线程应用程序,
- IO处理速度很快
- 异步回调模式,防止 JavaScript 代码被阻塞
- Node.js 使用 CommonJS 模块系统,而在浏览器中,则还正在实现 ES 模块标准。
node事件循环(生命周期)
宏
- timers队列,存放计时器得到回调函数,
- poll:轮询队列,除了timers和checks之外的绝大部分回调都会放入这个队列中(文件读取,监听用户请求)
如果poll中有回调,依次执行,知道队列清空
如果没有回调,等待其他队列中出现回调,结束该阶段,进入下一阶段
其他队列也没有回调,持续等待,直到出现为止 - check:检查阶段,使用setImmidiate的回调会直接进入这个队列
微: - nextTick > promise , 事件循环每次打算执行一个回调之前,必须先清空nextTick 和 promise队列
性能优化
https://zhuanlan.zhihu.com/p/113864878?from_voters_page=true
- js,DOM无限复用
- 长列表优化