目录
Html相关
Css相关
JavaScript相关
ReactJs相关
VueJs相关
webpack相关
Koa相关
Nodejs相关
Web相关
网络协议相关
浏览器相关
文档流(Normal Flow):也叫做普通流,就是html元素默认在页面中的排版布局,是相对于盒子模型来说的,比如div从上到下,span和p从左到右排列。
脱离文档流:就是将元素从排版布局中脱离出来,脱离文档流的方式:position中的absolute和fixed,还有float属性。
文本流:是指html中文本的显示,是相对于文字段落来说的,如果设置了绝对定位,元素即会脱离文本流也会脱离文档流。
DOM:Document Object Model是文档对象模型,dom是W3c的标准,DOM也定义了访问html和xml的标准,它允许脚本动态对文档进行操作。
BOM:Browser Object Model是浏览器对象模型,暂时还没有相关的标准,但是现当代的浏览器都已经实现了获取和设置浏览器的一系列的操作,比如获取浏览器屏幕分辨率,弹出框,打开关闭浏览器窗口。
web worker:是html5的一个新特性,让web应用程序可以具备多线程的处理能力,可以运行在后台的javascript,而不会影响页面其他正常处理和显示,可以将复杂需要时间的处理用web worker来处理。web work中不能操作dom元素。它的应用场景是,可以把一些阻塞页面渲染的一些js计算放到web worker中去做。
1.通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。
2.通过worker.postMessage( data ) 方法来向worker发送数据。
3.绑定worker.onmessage方法来接收worker发送过来的数据。
4.可以使用 worker.terminate() 来终止一个worker的执行。
web worker能做:
1.可以加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信
2.可以在worker中通过importScripts(url)加载另外的脚本文件
3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()
4.可以使用XMLHttpRequest来发送请求
5.可以访问navigator的部分属性
缺点:
1.不能跨域加载JS
2.worker内代码不能访问DOM
3.各个浏览器对Worker的实现不大一致,例如FF里允许worker中创建新的worker,而Chrome中就不行
4.不是每个浏览器都支持这个新特性
websocket:websoket是html5的一种新的网络协议,也是基于tcp的协议,它是持久的,可以持续在客户端和服务器端保持双工链接,服务器的更新可以被及时推送给客户端,不需要客户端再设置定时查询。
在网页中,一个元素的空间构成主要包括内容(content),边框(border),内边距(padding),外边距(margin)这些构成,这些就像实际中的盒子一样,所以叫做css的盒子模型。
BFC(Block Formatting Context)是块格式化上下文,简单来说就是一个独立的渲染区域,在bfc内部的元素不会影响到外面的元素,因为他们隔离互不影响的。
示例场景:比如两个div,同时设置margin:100px;这时候上下两个div的距离不是200px,而是100px,两个的外边距会重叠,这时候就需要用bfc来解决,分别用一个有bfc的div包裹着,这个bfc的div可以设置成overflow:hidden;来触发bfc即可。
触发条件:
1.根元素 float属性不为none
2.position为absolute或fixed。
3.display为inline-block, table-cell, table-caption, flex, inline-flex。
4.overflow为hidden。
css的选择器有哪些呢?
有id,类选择器,标签选择器,伪类选择器,属性选择器等等,具体参考: https://www.cnblogs.com/AllenChou/p/4684753.html
!import > 内联样式 > ID选择器 > 伪类选择器 > 属性选择器 > 类选择器 > 元素(类型)选择 > 通用选择器(*)
其实就是向上兼容和向下兼容浏览器,优雅降级就是向下兼容,渐进增强就是向上兼容
1.定义变量的符号不同,less是用@,sass使用$
2.变量的作用域不同,less可以作用在全局和所处的代码块中,而sass只作用于全局。
3.编译环境不同,less是基于javascript,在客户端环境处理,sass是基于ruby的,在服务器环境端处理。
px:实际就是像素,px是是相对于显示器分辨率的
em:是相对父元素计算字体大小,如果父元素没有设置大小,会以body的字体大小或者浏览器默认大小来计算。
rem:称为root em,也就是说是以根节点来计算,它是以根的字体大小来计算,不会依赖父元素,整个页面的字体大小设置好后都不会乱了。想多个端兼容,最好是使用rem。
1.在head标签中加一根meta标签,
2.使用媒体查询,即 @media 查询,媒体查询可以针对不同的屏幕尺寸设置不同的样式,通过控制screen的min-width和max-width。
3.使用rem来代替px,rem会根据html节点的字体大小来计算。而em呢是根据父元素节点大小,所以相对于还是rem更适合方便一些。
两者都是外部引用css样式的方式。
1.link是HTML提供的标签,不仅可以加载CSS文件,还可以定义rel连接属性等;@import是CSS提供的语法规则,只有导入样式表的作用;
2.link引用CSS时,在页面载入时可以同时加载;@import需要页面网页完全载入以后加载。
3.link支持使用js动态的去添加删除标签;而@import不支持。
垂直方向:line-height
水平方向:letter-spacing
1.设置父元素的font-size为0,然后设置子元素的font-size。
2.父元素设置letter-spacing为负值,子元素设置letter-spacing:0px;即可。
3.子元素用margin-left来调整。
4.子元素用float:left;来布局。
1.设置固定的高度,设置line-height。
2.设置父元素position:relative;子元素设置为position:absolute;top:50%;transform:translateY(-50%);意思通过设置translateY为-50%,就是自身的偏移量往上一半。
3.父元素设置postion:relative;子元素设置positon:absolute;top:0;bottom:0;margin:auto;
4.使用flex布局。display:flex;align-items:center;如果想水平居中,用justify-content: center;
5.父元素使用display:table;子元素使用display:table-cell;vertical-align:middle;
1.display:none;
2.visibilit:hidden;
3.opacity:0;
4.position:absolute;top:-999px;left:-999px;
5.transform: translateX(-500%);
比如:hello it's ok,使用text-transform:capitalize; 输出:Hello It's Ok
原始数据类型:Number,String,Boolean,Undefined,Null,Symbol
引用数据类型:Object,Array,Function,RegExp
有:undefined,object,boolen,string,number,function,ES6新增了symbol
1.常用骆驼命名法,首字母小写。
2.以字母,下划线,$符号开头,不能以中文,空格,特殊标点符号,数字开头。
3.变量命名尽量简洁和意思明了,不能过长。
4.不能使用js里面的关键字命名。
1.typeof可以判断一个变量是否为空,可以判断变量是属于哪个数据类型,比如返回undefined,string这些。注意的是对于 Array,Null 等特殊对象使用 typeof 一律返回 object。
2.instanceof是判断一个变量是否属于某个对象的实例
闭包是一个能够读取其他函数内部变量的函数。
优点:1.变量在内存中,可以提高性能。2.避免全局变量的污染。3.可以保护私有成员变量。
缺点:1.因为变量可以一直在内存中,所以内存消耗大。2.可能会导致不会被垃圾回收。
1.全局作用域:声明在函数外部的变量,在代码中任何地方都能访问的到(没有用var声明的变量属于全局变量哦)
2.函数作用域:函数内声明的所有变量在函数体内始终是可见的,可以在整个函数的范围内使用。
3.块级作用域:是es6有的一个概念,通过一对{}花括号定义的代码块,在这里定义的所有变量在代码块外面都是不可见的,这个就叫块级作用域。使用let和const定义的变量,只会在这一范围内起作用,也不会存在变量提升。
let和const是块级作用域,声明的变量不会存在变量提升,在未声明之前就使用变量就会报错,所以在代码块内,使用let和const声明变量,先使用后使用是不行的,这在语法上称为‘暂时性死区‘,简称TDZ。
constructor:返回对创建此对象的数组函数的引用。
length:设置或返回数组中元素的数目。
prototype :使您有能力向对象添加属性和方法。
concat() 连接两个或更多的数组,并返回结果。
pop() 删除并返回数组的最后一个元素。
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
shift() 删除并返回数组的第一个元素
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
reverse() 颠倒数组中元素的顺序。
slice() 通过下标截取数组
splice() 删除数组元素,并向数组添加新元素。
fill()将一个搞定的值填充一个数组中从开始位置到起始位置的所有元素
keys() 返回一个可以迭代的对象
sort() 对数组的元素进行排序
from()将一个类似数组或可迭代对象转换成一个数组
some()遍历时候,只要有一项满足,就返回true
every()遍历时候,全部都满足,才返回true
forEach()遍历数组
map()对数组中的每个元素进行处理,得到一个新的数组
filter()返回满足条件的数组元素
includes()判断数组中是否包含某一个值,会返回true和false
indexOf()判断数组中包含某一个值 ,存在则返回下标,不存在就返回-1
join()将数组中内容按照某个字符串分割,并返回分割后的字符串。
isArray()判断传递的对象是否是一个数组类型
toString()把数组转化为字符串
类是对象的抽象,对象是类的实例,对象是实际存在的,有对应的行为和属性。
1.块级作用域的let,const。
2.变量解构赋值。如let [a,b]=[1,2],输出是a=1, b=2
3.字符串的扩展,比如新增includes(),startsWith(),endsWith(),padStart(),padEnd(),matchAll(),字符串模版等。
4.函数的扩展,箭头语法,双冒号运算符,可以像bind一样将冒号前面的对象绑定到冒号右边,比如 foo:bar 相当于 bar.bind(foo)
数组和对象的扩展,新增了扩展运算符(...),用来合并数组和对象,不过这种是浅拷贝,数字也新增了from(),fill(),includes()等方5.法,对象也新增了Object.is(),Object.assign()浅拷贝的哦,Object.keys(),Object.values()等。
6.新增了Symbol原始数据类型。
7.新增了Set和Map,WeakSet,WeakMap,set里面的值是不会重复的,WeakMap和map区别是,WeakMap只能接受对象和null作为key。
8.新增了Promise对象,用来处理异步操作,可以通过then链式调用,来控制异步代码执行顺序。
9.新增了Generator和Async和await来处理异步,和Promise一样的作用,async返回的其实就是一个Promise对象。
10.新增了Class的语法,可以用extends来实现继承。
11.es6的import,export语法来实现模块化,其实和commonJS的module是一样作用的。
set是没有元素可以重复的,map是键值对可以允许重复
普通函数:只要是普通函数,即使是在箭头函数里面的普通函数,也是指向的window,严格模式下是undefined。
实例化对象或者字面量对象:这种是该对象调用了,this就指向这个对象,如果对象里面的一个普通函数调用了,还是指向的window,如果是箭头函数调用了,就指向当前的这个对象。
箭头函数:根据所在的环境,在哪个环境就指向谁。
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数的函数,并返回一个函数接受剩下的参数。这中间可嵌套多层这样的接受部分参数的函数,直至返回最后结果。
例如:
function add(a){
return function(b){
return function(c){
return a+b+c;
}
}
}
console.log(add(1)(2)(3));
输出结果:6
1.apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, argsArray); 即A对象调用B对象的方法。
2.call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2); 即A对象调用B对象的方法。
3.参数不同,call可以接受多个参数,apply职能接受的一个数组参数。
4.call和apply可以重新修改this的指向。
主要是直接修改对象的prototype就可以了,就不是同一个实例了,比如下面:
function Cat(){
this.name='cat'
}
var cat = new Cat();
Cat.prototype ={
say:function(){
console.log('a cat')
}
}
console.log(cat instanceof Cat) // 这里输出false
构造函数也是普通的函数,只不过会通过new来调用并创建一个新的示例,这个函数就叫做构造函数。
原型:就是函数创建的时候都有一个prototype属性,这个就叫原型,也称为显示原型。我们用构造函数创建的对象会有prototype上面所有绑定的方法。
原型链:当我们用obj.xxx访问一个对象的属性时,会先在对象自身属性中查找,找到就返回。如果没有找到,再沿着__proto__这条链向上找,找到返回。如果找到原型链的顶层Object.prototype还没有,就返回null,也就是 Object.prototype.__proto__ === null。
①prototype(原型)是构造函数才有的属性,可以叫做显示原型,它实例化的对象包含prototype上所有共享的方法。(当构造函数new实例化一个对象时候,它实例化对象的__proto__指向了它构造函数的prototype);
②__proto__ 是对象(不论是普通对象还是构造函数实例化的对象)才有的属性,可以叫做隐式原型,用于指向创建它的构造函数的原型对象。(对象的__proto__会指向它构造函数的prototype);
function foo(){}
var f = new foo();
// 该实例化的对象的__proto__指向了其的构造函数prototype
console.log(f.__proto__ === foo.prototype) // 输出:true
var obj = {}
// __proto__指向构造函数的prototype
console.log(obj.__proto__ === obj.constructor.prototype) // 输出:true
// 为
元素添加 class: document.getElementById("myDIV").classList.add("mystyle"); // 为
元素添加多个类: document.getElementById("myDIV").classList.add("mystyle", "anotherClass", "thirdClass"); // 为
元素移除一个类: document.getElementById("myDIV").classList.remove("mystyle"); // 为
元素移除多个类: document.getElementById("myDIV").classList.remove("mystyle", "anotherClass", "thirdClass"); // 为
设置属性 document.getElementById("myDIV").setAttribute("title","this is a title");
1.大量声明使用全局变量。2.闭包引起的内存泄漏。3.dom清空或者删除时候,绑定的事件未清除。4.定时器未被清除。5.子元素存在引用。
标记清除:
当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:"离开环境"。然后圾回收器会过滤掉环境中的变量以及被环境中的变量引用的变量,剩下的就是被视为准备回收的变量。
引用计数:
机制就是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给该变量时该值引用次数加1,
当这个变量指向其他一个时该值的引用次数便减一。当该值引用次数为0时就会被回收。
这两个的值是不相等的,即undefined === null 是 false。undefined表示变量定义了未赋值,null表示变量的引用是空的。
注意(null == undefined)为true,是成立的,因为在ecmascript规范中,null和undefined的行为很相似,都表示一个无效的值,所以它们是相等的。
CommonJS, AMD, CMD都是JS模块化的规范。
1.CommonJs 是服务器端模块的规范,Node.js采用了这个规范。 根据CommonJS规范,一个单独的文件就是一个模块,加载模块使用require方法,CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。
2.AMD(Asynchronous Module Definition) 是 RequireJS (这里可以简记amd和requirejs是AR眼镜)在推广过程中模块定义的规范 ,AMD异步加载模块,AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块 。
3.CMD(Common Module Definition)是SeaJS (这里可以简记cmd和seajs是打游戏的CS)在推广过程中模块定义的规范。CMD推崇就近依赖,只有在用到某个模块的时候再去require模块 。
1.什么是事件流?
也就是事件处理的流程,是有先后执行顺序的,标准的事件流它分为3个阶段:①事件捕获 ②事件目标 ③事件冒泡
2.什么是事件模型?
就是事件的一个标准模型,分为3个模型。分别是:
①原始事件模型(DOM0)
在原始事件模型中,事件发生后没有传播的概念,也没有事件流的产生,事件发生后就马上处理然后结束,比如:
document.getElementById("btn").onClick=function(){alert('hello')}
②IE事件模型
这个是在ie系列浏览器里支持的,ie中的事件流不是标准的,它只有事件目标和事件冒泡,没有事件捕获,ie中创建事件是用attachEvent('onclick',function(){});移除用detachEvent('onclick',function(){}): 注意的是ie中组织事件冒泡的方法是获得event对象,这个event对象是用的全局变量window.event获得的,而且函数执行完毕,这个event就是null了。
③DOM2事件模型
这个模型是W3C指定的标准模型,我们现在用的浏览器都是按照这个标准,在W3C指定的事件模型中,一次事件的发生包含3个过程:
* 事件捕获(事件被从document一直向下传播到目标元素,在这过程中依次检查经过的节
点是否注册了该事件的监听函数,若有则执行。)
* 事件处理阶段(事件到达目标元素,执行目标元素的事件处理函数)
* 事件冒泡阶段(事件从目标元素上升一直到达document,同样依次检查经过的节点是否注册
了该事件的监听函数,有则执行。)
添加事件:document.getElementById('div').addEventListener('click',function(){},false)
addEventListener第三个参数是false就是事件冒泡,是true就是事件捕获。
删除:removeEveentListener('click')
说到事件委托,其实和事件代理是一个意思,都是表示有一个第三方去做某件事情。
委托就是把事件监听函数绑定到父元素上,让它的父辈来完成事件的监听,这样就把事情“委托
”了过去。在父辈元素的监听函数中,可通过event.target属性拿到触发事件的原始元素,然后
再对其进行相关处理。
举个例子,比如我们去饭店吃饭,小明说想吃蛋炒饭,小花说想吃牛肉面,小明和小花不可能直接告诉厨师吃什么,人多的话厨师记不清,这时候服务员出来了,服务员记录下来小明和小花想吃的饭,然后报给厨师,做好后,服务员根据做好的饭和订单上对应(event.target判断),依次给小明和小花, 这个服务员就是个委托,也是代理。
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com是读取不了b.com下面的资源。
不受同源策略限制的有:
1、页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
2、跨域资源的引入是可以的,如嵌入到页面中的,,,
跨域就是前面说的同源策略影响的解决办法,就是跨域。
跨域的方式有:1.jsonp跨域。
2.通过修改document.domain来跨域。
3.cors实现跨域,主要是后端配置Access-control-allow-origin来实现。
4.nginx做代理也可以实现,配置proxy_pass地址。
5.在开发环境下也可以实现,比如可以在package.json中配置proxy。
具体也可以参考:https://segmentfault.com/a/1190000011145364
作用域:作用域其实就是变量或者函数起作用的范围,比如定义一个var a在一个函数里,那这个a的作用域就是在这个函数里,外面是访问不到的。
作用域链:是javascript内部中一种变量、函数查找机制。进入执行环境后,访问一个变量时候js引擎会在当前作用域往上去找,知道找到global全局作用域为止,和原型链有一点相近,也是逐级往上去寻找,但是作用域链的顶层是window。
栈先进后出,基本数据类型和变量放到栈中,new的对象是放到堆中
1.创建一个空的对象(var person = {};)
2.将这个对象的__proto__属性指向构造函数的prototype对象(person.__proto__ = Person.prototype;)
3.使用新对象调用函数,函数中的this被指向新实例化的对象(Person.call(person);)
4.将初始化完毕的新对象的地址,保存到左边声明的变量中。
1.在script标签中使用async属性,虽然可以实现,但是它是乱序执行的,只要加载完了就会执行,所以不能保证执行顺序。
2.在script标签里使用defer属性,JS的执行在所有元素解析完成之后进行,而且它是按照加载顺序执行脚本的
3.动态生成script标签,在onload里动态使用document生成标签。
1.直接通过字面量创建var obj = {};
2.直接通过new Object()方式创建。
3.工厂模式
4.构造函数模式
5.原型模式
6.组合模式
1.原型链继承。
2.es6的extends继承。
3.构造函数继承。
4.组合继承。
5.寄生式继承。
==:叫做相等运算符,比较时候会进行类型转换,值相等就是相等。
===:叫做严格运算符,只要类型不用,就不会相等。
sessionStorage 、localStorage 和 cookie 之间的区别?
共同点:都是保存在浏览器端、且同源的
区别:
1、创建方式不同:cookie是由服务器端创建,发送客户端,当用户发送请求后,会在http请求中携带传递到服务器端。而sessionStorage和localStorage是创建保存在客户端,也不会自动把数据发送给服务器。
2、存储大小不同:cookie数据不能超过4K,只适合保存很小的数据,比如会话标识。sessionStorage和localStorage本地存储可以达到5M以上。
3、数据有效期不同:sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭 。
4、作用域不同:sessionStorage只能在同一个浏览器页面中有效,或者打开链接和用window.open新打开一个页面也可以有效的,除了这些其他的情况都是不能共享的;localstorage和cookie都可以在所有同源窗口中都是共享的;
5、web Storage支持事件通知机制,可以将数据更新的通知发送给监听者,具体是在页面添加监听事件:window.addEventListener("storage", handleStorage, false);
6、web Storage的api接口使用更方便,比如setItem,getItem,removeItem,clear都可以很方便的操作。cookie必须自己手动封装。
1.创建XMLHttpRequest对象
2.判断数据传输方式(get,post)
3.打开open("get","www.abc.dom?id=1"),建立连接,传输参数。
4.发送send()
5.通过判断http的响应状态来接收数据,主要是在onreadystatechange里来判断 if(readyState=4和status=200){} 即可。
event loop称为事件循环机制,javascript是单线程的,所有的任务都需要排队执行,javascript把任务分为两种,一种是同步任务,一种是异步任务,同步任务就是在主线程排队执行的任务,需要一个一个的按顺序执行,异步任务是会进入到任务队列里(task queue),只有任务队列通知主线程某个异步任务可以执行了,该任务才会进入到主线程执行。任务队里还分为宏任务(setTimeout等)和微任务(Promise),进入任务队列是像进入栈一样,先进后出,先进入宏任务,再进入微任务,但是最终是先执行微任务,再执行宏任务,完了之后就会再重新到主线程执行,这样来回循环的执行其实就是事件循环机制。
防抖:当持续触发事件时,在一定时间内事件执行,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
// 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer); // 清除未执行的代码,重置回初始化状态
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数,下次执行事件就需要下个时间段内执行。
// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){
// 判断是否已空闲,如果在执行中,则直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
解构赋值语法是一种js表达式,它使得将值从数组,属性,对象中提取到不同变量里。
比如:[a,b]=[10,20],结果是a=10,b=20;
1.使用for循环来比较
let num = 0;
for(let i = 0;inum){
num=i;
}
}
2.使用es6的语法
var n = Math.max(...array)
第一种:直接用数字的原型方法
var num = 123456789;
num.toLocaleString();
第二种:使用正则
var num = 123456789;
var str = num.toString().replace(/(?=(?!(\b))(\d{3})+$)/g,",");
React 是一个用于构建用户界面的 JAVASCRIPT 库。 React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图),React是Facebook开发的一个项目,它是单向数据流的,和vue数据双向绑定不同。
1.函数组件只能接收props。
2.使用es6 class创建的可以不单可以使用props,还可以使用this,和state,以及生命周期函数。
1.在constructor里bind
constructor(props){
super(props);
this.handleClick=this.handleClick.bind(this);
}
2.使用属性初始化器语法
handleClick = () =>{}
3.在元素中的事件使用箭头函数
this.handleClick(id,e)}>click me
4.在元素的事件中也可以使用bind
click me
虚拟dom其实就是用一个对象来描述dom树,对数据和状态的变更会同步到虚拟dom上,通过计算新旧虚拟dom的差异,最终把变化的部分重新渲染。
diff算法是实现比较虚拟dom差异的一个算法,它可以对虚拟dom进行逐层的比较,如果树类型不同,就会重新创建,如果类型相同,属性不同,就会只更新属性不同的部分,如果在子节点后新增节点,会直接增加节点,如果在子节点前增加节点,会重新生成这几个节点。
给节点加key,key更方便diff算法计算出来节点之间的差异。
element:元素是构成react应用的最小单位,用来描述页面上看到的内容,可以用jsx语法创建一个元素,比如const element=
component:组件就是一个方法或者一个类,可以接受任意的输入值(称之为props),并且返回一个需要在页面上展示的react元素。
Redux是一个流行的JavaScript框架,为应用程序提供一个可预测的状态容器。
那什么是可以预测化,我的理解就是根据一个固定的输入,必然会得到一个固定的结果。
核心概念,三大原则:①单一数据源 ②state是只读的 ③使用纯函数执行修改
处理流程,主要是action,reducer,store,
组件dispatch一个action,然后到reducer,reducer是一个纯函数,它接收到这个action,根据action的类型,来更新状态。
缺点:
1.修改一个state可能要动4,5个文件,修改复杂。
2.每次dispatch一个action都会遍历所有的reducer,重新计算connect,很费效率。
3.如果store较大时候,频繁的修改store,会明显看到页面卡顿。
4.不支持typescript。
thunk和saga是redux的异步解决方案,thunk可以接受一个函数并且可以在里面dispath action,但是缺点是action的调用会分散在各个文件中,不易管理。saga的优点是action统一管理,集中处理异步操作,但是个人觉得saga可能初学起来不是太容易,需要先学习es6的yield和async以及await语法。
mobx是一个简单的可扩展的状态管理框架。它通过@observable定一个被观察的状态数据,state的修改是在action函数中进行,并且提供了computed,通过get和set也可以计算state,它比起redux更加的简洁明了,在页面中是通过@inject("store")注入store,并且把组件@observer变为观察的组件。
这两个框架都是可以做react状态管理的,mobx很简洁,上手很快,原理也是比较简单,从页面发起action到对应的action去处理state,大量使用了装饰器语法。不需要花大量的时间去研究即可上手编写。
redux则比较庞大一点,它的衍生出来的框架也有thunk和saga,学习saga需要学习es6的await,yield,async语法,学习成本和维护成本高一点。
redux是单数据源的,其中一个原则是单一数据源,你需要将所有的state放到一个全局的store里面,而mobx相反,它可以@observable观察多个state,也就是可以由多个数据源。
分为4个阶段:初始化阶段,挂载阶段,更新阶段,卸载阶段
初始化阶段:
defaultProps={}:设置默认的props
constructor() :这里可以获得props和初始化state
挂载阶段:
componentWillMount() :组件被挂载到页面之前调用,这时候还无法获取dom对象。
render() :渲染组件到页面中,这里注意不要使用setState,否则会递归渲染。
componentDidMount():组件已经挂载到页面,dom也可以获得到,也可以发送ajax请求,也可以修改state状态,但是注意这里修改状态会重新渲染。
更新阶段:
componentWillReceiveProps() :组件接收到新的props会触发这个方法,修改state不会触发这个。
shouldComponentUpdate() :这个方法返回true和false,来决定是否重新渲染组件,性能优化就是在这里进行。
componentWillUpdate() :组件将要更新时候调用。
render() :重新渲染组件,这个函数能够执行多次,只要组件的属性或状态改变了,这个方法就会重新执行
componentDidUpdate():组件已经被更改过了,会调用这个方法。
卸载阶段:
componentWillUnmount():组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
1.bind函数的使用,在constructor中bind进去,因为构造函数每次渲染只会执行一次,在jsx模版中bind会每次render都会执行。
2.shouldComponentUpdate里进行优化,这个钩子可以返回true和false,false的话就是不渲染,可以在这里面决定是否渲染组件。
3.组件继承React.PureComponent,因为它比React.Component性能更好,当props和state改变的时候,PureComponent会对它们进行浅比较,来决定是否渲染组件,而Component不会进行比较,当shouldComponentUpdate被调用时候,组件默认会重新渲染。
4.使用redux和mobx这些框架来管理状态。
5.props尽量只传递需要的数据,多余的就尽量不要代入过去了。
6.如果有组件循环,需要指定key。
react是单向数据流,所以不像vue和angular一样可以自动实现检测到数据变化,react是需要主动触发数据变化,比如setState时候,就可以触发更新。
vue是一套用于构建用户界面的渐进式框架,它的核心是数据驱动和组件化。
我们可以只用我们想要的一部分功能,不必像其他框架一样必须强制接受例如依赖注入这些,没有强侵入性,自由灵活。
当vue的实例被创建的时候,Vue 将遍历data中所有的属性,并使用Object.defineProperty将它们转为getter/setter,vue追踪它们内部的相关依赖,在属性被访问和修改时候通知变化。
每个组件都有响应的watcher实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新
分为4个步骤,创建,挂载,更新,销毁。
1.创建
beforeCreate();
created(); // 初始化的内容写在这里,比如请求ajax进行数据处理
2.挂载
beforeMount();
mounted(); // dom渲染在这里就已经完成了,可以获取到dom节点
3.更新
beforeUpdate();
updated();
4.销毁
beforeDestroy();
destroyed();
第一次页面加载会触发:beforeCreate,created,beforeMount,mounted这几个钩子函数,而且dom渲染在mounted中就已经完成了。
在vue的created()钩子中操作dom,需要用到$nextTick()这个函数,因为这时候dom元素还没有渲染完毕,我们取dom元素是取不到的,这个函数是可以在dom更新之后,把操作放到它的回调函数里。
直接在生命周期里绑定document.οnkeydοwn=function(e){}即可。
监听事件除了keycode对应的数字之外,vue还添加了事件的别名,比如enter,tab,delete,esc,space等。
vuex是一个专门为vuejs设计的状态管理工具,在状态比较多难以管理的时候就用它。
state:状态数据,可以通过modules来配置多个数据源操作。
getter:返回计算处理state后的函数,相当于react-mobx中的computed和vue中的计算属性。
mutations:真正处理state的地方。
action:用户提交的action操作,view 层通过 store.dispath
来分发 action。
modules:如果管理状态的业务比较复杂,可以分为几个模块,最后在vuex中使用模块,引用的时候加上模块的名字即可。比如:
const moduleA = {
state: { name:'this is a name' },
mutations: { },
actions: { }
}
const store = new Vuex.Store({
modules: { moduleA }
})
this.$store.state.moduleA.name; // 使用的时候加上模块的名称
流程是;用户在view上dispatch一个action》vuex的actions接收到后commit这个action到mutations》mutations更改state的数据状态》可以通过vuex提供的getters展示到view,也可以在view里this.$store.state.text来获取状态数据。
需要在action中做异步处理,不在mutation中处理是因为vuex官网上也有说,mutation是必须是同步的函数,mutation操作写异步的话状态很难追踪,这样就会造成很多问题。Action和Mutation的区别是,action提交的是mutation,而不是直接操作state,action中是可以包含任何异步的操作。在action中同步就需要return new Promise(),或者是使用async来定义action,这样在异步处理的时候才会同步去执行。
Promise是异步处理的一种解决方案,多个异步的处理不需要通过回调函数来处理,es6提供的promise处理后可以返回一个resolve,异步执行完后执行resolve()就会执行then里面的代码,这样使异步不再变得不可控,甚至可以多个then链式调用来控制异步代码的执行顺序。
Promise中有3种状态:
pending:初始状态,既不是成功也不是失败
fulfilled:意味着操作完全成功
rejected:意味着操作失败
同一时间只有一个状态存在,且状态改变就不能再变了,当调用resolve()时候会执行后面的then,当执行reject()就不会继续进行下去。
登录等信息存储的数据保存到sessionStorage中最好,长久保存的信息保存到localStorage中,当刷新页面时候,重新合并获取到的数据到store中。
参考:https://segmentfault.com/a/1190000013763590
通过compile编译器把template编译成AST抽象语法树(Abstract Syntax Tree),之后generate函数会递归解析ast抽象语法树生成render函数,render的返回值就是vnode(虚拟dom的节点),里面包含标签名,子节点,文本等,最后会更新视图。
相同点:
1.都可以做spa单页面应用。
2.都支持服务器端渲染
3.都有Virtual Dom,页面的操作数据会反应到虚拟dom上,通过diff算法计算后再渲染到页面。
4.都有组件,都有props,并且支持父子组件之间通信,也都有状态管理工具,react的redux,mobx和vue的vuex。
5.都有生命周期。
不同点:
1.react是mvc框架,vue是mvvm框架。
2.react是单向数据流,用事件来操作数据改变状态,vue是双向数据绑定,通过数据劫持和订阅者观察者来实现。
3.写法不同,react用的是jsx模版,vue就像是写一个普通HTML页面一样,同时可以包含有css和js。两者在渲染数据,更改data是不一样的写法,react渲染是必须return元素在下面引用,vue是直接在标签上用指令就可以,react用setState设置数据,vue直接用等号就可以。
4.数据发生改变,vue会自动跟踪组件的依赖 关系,不需要重新渲染组件数。而react则状态改变,全部组件都会重新渲染,所以需要在shouldComponentUpdate这个生命周期里来优化
会更新视图的方法:push(),pop(),shift(),unshift(),splice(),sort(),reverse()还可以使用Vue.set( target, key, value )
不会更新视图的方法:filter(),concat(),slice()
mvc:(Model模型-View视图-Controller控制器),mvc是最经典的开发模式之一,流程是用户操作,view层负责接收输入,然后到Controller控制层,对Model数据进行处理,最后将结果通过View反馈到用户。mvc的通信是单向的,简单说就是:
用户-View-Controller-Model-Controller-View,缺点是:M和V层耦合度高,所有逻辑都在C层,导致庞大难以维护。
mvvm:(Model模型-View视图-ViewModel视图模型),也就是数据双向绑定模型,Model和View之间解耦,通过ViewModel进行交互,它就是一个同步View和Model的对象,View和Model之间的同步是自动的,不需要人为干涉,开发者只需要关注业务逻辑,不需要手动操作Dom。
概念:它是vue的一个内置组件,主要作用是保留组件的状态,避免重新渲染。
它是一个抽象组件,不会被渲染到真实DOM中,它提供了include与exclude两个属性,允许组件有条件地进行缓存。
原理:其实就是在created时将需要缓存的VNode节点保存在this.cache中/在render时,如果VNode的name符合在缓存条件(可以用include以及exclude控制),则会从this.cache中取出之前缓存的VNode实例进行渲染。
因为可以给每个遍历元素添加一个唯一标识,可以让diff更快的计算出来进行渲染。
在当前的vue页面中的style标签纸红加上scoped即可,如:
数据驱动和组件化
数据驱动:简单可以解释为数据(Model)的改变,使视图(View)自动更新。也就是数据双向绑定,Model的改变会通过ViewModel改变View,同时也会监听View的变化,也会通过ViewModel响应到数据Model,实现数据双向绑定。
组件化:组件化实现了可扩展和可重用可维护的html元素,通过封装可用的代码,页面上每个独立交互的功能都可以抽取出来成一个组件。
可以参考:https://blog.csdn.net/twodogya/article/details/80223508
首先每一个组件其实都是一个vue实例化得来的,引用的是同一个实例,所以一个发生改变,其他的引用肯定也会改变的,但是换成函数的话,因为变量在函数里外部不能直接访问,所以也就不会影响到别的组件。所以new vue的时候实例其实只有一个,用data:{}也就可以了。
1.自己搭建个简单的express服务器访问静态的json文件。
2.使用vue-cli里面提供的express服务器,配置路由地址,返回json文件即可。webpack4的版本需要在配置文件中配置before(app){}钩子才可以,和webpack3配置的位置不同。
1.在组件中自定义过滤器
在组件中写:
filters:{
myFilter(value){
return value.toLowerCase();
}
}
使用:
直接输出属性时候{
{name | myFilter}}
或者在v-bind中
2.自定义全局过滤器
Vue.filter('allFilter', function (value) {
return value.toLowerCase();
})
new Vue({
// ...
})
参考官方的文档的写法,指令是有几个钩子函数的,bind,inserted,update等,具体的含义和使用参考https://cn.vuejs.org/v2/guide/custom-directive.html
1.计算属性可以用来计算模版中比较复杂的逻辑,运算,并且它需要返回一个结果。
2.计算属性监听vue中的数据依赖,只要依赖的其中一个数据变化了,就会重新计算,相当于watch监听数据一样。
3.计算属性还可以依赖其他vue实例中的数据,比如new vue实例有A和B,A可以获得B的data中的数据进行计算。
4.计算属性还可以进行缓存,只要依赖的数据没有变,再次请求也不会重新计算,而是去取的缓存。
安装vue-cli全局后,可以使用命令vue create myapp根据命令行创建应用,也可以使用vue ui命令打开一个界面,使用图形化的页面创建应用。
1.父-子:调用子组件
2.子-父:调用子组件
3.定义公用组件bus来传值,父组件用bus.$on("fromChild",fnction(data){});子组件用bus.$emit("fromChild",传的值);
4.使用Vuex来传值。
第一种:定义一个全局变量的vue页面,在每个需要引用的页面import进来。
第二种:全局变量挂载到Vue.prototype原型上。
Vue.prototype.color="红色";
Vue.prototype.getColor=function(){return "红色";}
在vue页面中直接可以{
{this.color}} {
{this.getColor()}}来使用
第三种:在main.js的同级目录创建一个global.js,里面需要放到install里
exports.install = function (Vue, options) {
Vue.prototype.getColor = function (){
return "红色"
};
}
最后在main.js中Vue.use(global)即可,页面中的使用方法还是{ {this.getColor()}}这样即可。
import global from './global'
Vue.use(global)
第四种:使用Vuex来做全局的变量,也可以在任何页面都能够获取。
页面路由跳转时候,如果从/use/a调到/use/b,这时候组件是会复用的,不会重新创建,所以想对路由参数变化作出响应的话,就需要使用watch来监听$route对象。或者在组件中使用beforeRouteUpdate(to,from,next){}钩子函数来监听。
导航被触发。
在失活的组件里调用 beforeRouteLeave 离开守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫
在路由配置里调用 beforeEnter 守卫。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve守卫
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
1.全局钩子:定义在全局的路由对象中,beforeEach,afterEach
2.单独路由定义的钩子:可以直接定义在路由配置上,beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave
路由文件:
import HelloWorld from '@/components/HelloWorld.vue'
export default new Route({
router:[
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: HelloWorld}
]
})
匹配的使用方法:
hi页面
// 会请求/user/1
this.$router.push({name:'/user',params:{id:1} })
由多个层次构成的路由就是嵌套路由,每个路由的父级定义
这个标签相当于a标签,用来做路由的跳转。
to: 属性是路由的地址。
replace: 跳转后不会留下history记录。
tag :把router-link标签变为某个标签,比如li,span,等
active-class:当链接被激活的时候使用的class样式。
第一种,普通的加载方式
import Hello from 'Hello.vue'
const router = new VueRouter({
routes: [
{ path: '/hello', component: Hello }
]
})
第二种,vue动态组件实现的懒加载
const router = new VueRouter({
routes: [
{
path: '/hello',
component:(resolve) =>{
require(['@/components/Hello.vue'],resolve)
}
}
]
})
第三种,es6的import实现的懒加载,推荐这种,vue-router官方也写的这种。
const Hello = () => import('@/componsnts/Hello.vue')
const router = new VueRouter({
routes: [
{ path: '/hello', component: Hello }
]
})
vue路由有两种模式,hash和history,默认是hash,前端路由的核心就是改变页面路径的同时不会向后台发送请求。
hash:地址栏有带一个#号,比如:http://www.abc.com/#/hello,刷新页面和前进后退都可以用。这个是不会请求后台的,是前端页面中使用的路由。
history:需要在路由里配置mode为history,利用了html5的history新增的 pushState() 和 replaceState() 方法方法,比如http://www.abc.com/user/1,这种请求的路径需要和后台匹配的,不然会返回404找不到资源。
$route是路由信息对象,包括path,params,query等路由参数,而$router是路由实例,包括了路由的跳转方法this.$router.push(),this.$router.replace(),this.$router.go(),this.$router.back()等,和一些钩子函数router.beforeEach(),router.afterEach()等。
webpack是一个前端模块化打包工具,可以把项目中的资源打包成浏览器可以识别的资源。主要由entry入口,output出口,loader,plugins四个部分。
bundle:是由webpack打包出来的文件,
chunk:是指webpack在进行模块的依赖分析的时候,代码分割出来的代码块。
module:是指开发中的单个模块。
loader是打包时候用于转换某些类型的模块,比如处理js,css,图片等类型的
plugin就是打包用到的插件,可以参与到打包的流程中,比如最长用到的htmlPlugin,可以把js和css打包到html模版文件中。
webpack
1.初始化配置参数
2.绑定事件钩子回调
3.确定entry文件并遍历
4.使用loader和plugin编译解析文件
5.输出文件
1.定位体积比较大的模块,可以用webpack-bundle-analyzer插件来查看。
2.提取公共模块。
3.移除不必要的文件。
4.可以通过cdn引入一些库文件,可以见效打包文件的体积。
5.利用缓存。
6.更换js的压缩插件为uglifyjs-webpack-plugin。
7.使用dllpllugin,这个插件可以实现把依赖的第三方的包(比如react,vue,jquery)完全分离开,因为这些第三方包不会经常改变,除非是版本升级,所以这些第三方包只需编译一次,生成*.dll.js文件,以后每次只打包项目自身的业务代码,可以提高编译速度。
7.因为webpack是单线程的,所以可以使用happypack用多个进程并行处理,可以提高打包速度。
webpack和gulp都是前端自动化构建工具,但是他们的定位不一样,webpack侧重于模块打包,根据模块之间的依赖,生成最终生产部署的前端资源。
gulp侧重于前端开发的流程,在gulpfile.js里通过配置task任务使用一些插件,来实现js,css压缩,图片压缩,编译less,热加载。gulp利用流的方式进行文件的处理,gulp处理的文件是写在内存中,通过管道将多个任务和操作连接起来,所以处理更快,流程更清晰。
1.autoprefixer 自动补全css3的前缀
2.html-webpack-plugin 生成html文件,可以使用指定的模板html。
3.extract-text-webpack-plugin 打包时候分离css,形成独立的文件
4.copy-webpack-plugin 拷贝文件和文件夹到指定目录,也可以配置ignore忽略文件。
5.webpack.ProvidePlugin 自动配置全局加载模块,比如配置jquery,不用每次都import使用。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
6.HotModuleReplacementPlugin 模块热替换插件,修改可以实时看到。
7.uglifyjs-webpack-plugin webpack4中的压缩js插件
8.clean-webpack-plugin 清理打包目录插件,可以配置清理的文件夹目录
9.happypack webpack是单线程的,这个插件是可以多线程执行任务,加快编译速度
10.webpack-dev-server 启动server后,可以把打包的文件存储到内存中,这样可以使用热加载功能,修改代码不需要刷新页面。
webpack自定义插件可以通过es6的class写一个类,或者用函数,最后再模块导出,在webpack.config.js中new插件即可。
第一种实现方式,使用函数方式,并且在函数的原型上绑定apply方法
function MyHelloPlugin(options){
console.log('接收插件的参数:',options)
}
MyHelloPlugin.prototype.apply = function(compiler){
compiler.plugin('emit', function(compilation) {
console.log('生成资源到output目录之前:',compilation);
});
compiler.plugin('done', function() {
console.log('编译完成了');
});
}
module.exports=MyHelloPlugin;
// 在webpack.config.js中引入并入使用
const MyHelloPlugin = require('./webpack.myplugin.js')
new MyHelloPlugin({option:true})
第二种方式,使用class,并在里面添加apply方法
class MyHelloPlugin{
constructor(options){
console.log('传递的参数:',options)
}
apply(compiler){
compiler.plugin('done',function(compilation){
console.log('编译完成')
})
}
}
module.exports=MyHelloPlugin;
// 在webpack.config.js中引入并入使用
const MyHelloPlugin = require('./webpack.myplugin.js')
new MyHelloPlugin({option:true})
以上两种方式都可以,但是必须要写apply方法,因为自定义插件运行的时候会自动应用插件对象绑定的这个apply方法。
apply方法的回调返回一个compiler对象,这个对象是继承自Tapable类,compler可以监听整个编译的过程,它里面包含整个webpack声明周期钩子,比如有beforeRun,watchRun,run,beforeCompile,compile,compilation,emit,afterEmit,done,watchClose等等钩子。
Tapable这个类暴露很多的钩子函数,compiler中的钩子其实用到的是这里面的,比如写插件需要的plugin方法,apply方法都是继承的tapable里面。这个类的作用实际上就是一个事件管理器,是一个基于发布订阅者的模式,专注于事件的触发和处理。
compiler的钩子的回调是返回一个Compilation对象,这个对象是继承Compiler,它的主要作用是在打包的过程中可以获得打包的模块和依赖,同时也提供了一些钩子函数,在这个阶段模块可以被加载(loaded),封存(sealed),优化(optimized),分块(chunked),哈希(hashed),重新创建(restored),当然它也是属于compiler声明周期中的一个钩子。
是koa中的一个插件,可以处理请求和实现上传文件等操作,可以代替请求处理的koa-bodyparser和图片文件上传的koa-multer。
pm2是一个node进程管理器,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。
web标准是一些列标准的集合,主要包括 结构,表现,行为。
结构标准:是指用html,xhtml,xml来描述页面的结构。
表现标准:是指使用css样式来美化页面结构,使它更具有美感。
行为标准:是指用户和页面之间有一定的交互,可以使页面结构和表现发生改变,比如W3c制定的EcmaScript标准来实现。
可用性:是指页面从用户的感官上来说是否容易上手,容易理解,容易操作完成,可用性好说明产品质量高。
可维护性:是指系统出现问题时候可以快速定位解决,成本低,可维护性高,而且代码结构是否清晰符合标准,让其他的开发者更容易上手维护。
可访问性:是指在不同浏览器,不同屏幕下是否可以很好的去展示,并且对不同的用户或者有残疾的用户是否都可以使用。
使用语义适当的标签去构建html页面的结构,比如使用h1-h6设置标题,使用header,footer,nav,aside标签来划分结构。html语义化可以使html的页面结构变得更加清晰,即使没有css的情况下页面也能够很好的呈现出结构,还能提升用户体验,方便维护,方便爬虫抓取和seo搜索引擎优化,也便于不同设备之间的访问。
网页可以在不同尺寸的设备上面可以自动调整显示和布局,以适应不同尺寸屏幕的浏览体验。
1.sql注入:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
2.xss攻击:指的是攻击者往Web页面里注入恶意脚本代码,当用户浏览网页时候执行恶意代码来窃取用户的信息。
3.csrf攻击:指的是打开未受信任的网站,导致本地存储的cookie和个人信息泄露,而造成的被盗用了个人信息。比如你刚转了钱,本地保存了你的银行的个人信息,接着你又不小心访问了一个网站,这个网站就会盗取你的信息,去盗取你的银行信息。
优化的目的:
用户角度:网页加载速度快,操作响应及时,用户体验好。
服务商角度:能减少页面请求、和占用的带宽资源,提高服务器的处理响应速度。
主要分为:
①页面级别优化
1.减少http请求。
2.使用外部脚本和css,可以缓存下来。
3.打包资源优化。
4.避免请求重复的资源,减少不必要的http跳转。
5.按需加载资源,比如js和图片懒加载。
6.从设计层面上简化页面,避免过于复杂的交互操作。
7.把js放到底部,把css放到header,可以避免造成阻塞。
8.使用骨架屏,可以用base64图片代替展示,数据加载完了就替换当前图片。
②代码级别优化
1.减少dom的操作,避免重绘和回流而影响页面性能。
2.减少闭包的使用,因为闭包的变量都会在内存中,过多会造成内存消耗。
3.css优化,减少使用行内标签,可以用类和标签选择器,同样的功能建议抽取出来一个common css。
4.在手机端的页面,可以添加样式transform:transition3d(0,0,0)来开启硬件加速,会使页面流畅。
5.避免大量的声明全局变量,因为这些变量会绑定到window全局变量上,会可能造成内存溢出。
③服务器优化
1.提高硬件环境。
2.优化nginx,比如加大进程数,配置gzip压缩减少网络上所传输的数据量,配置超时时间,缓存等
1.尽量使用css3的动画开启硬件加速,比如transform:transition3d(0,0,0)。
2.使用touch事件代替click事件。
3.避免使用css3的阴影效果。
4.不滥用float,因为float在渲染时候计算了比较大,会影响性能。
5.不滥用web字体,web字体需要下载,解析,重绘,尽量减少使用。
6.pc端的性能优化同样适用在手机端。
Web语义化是指使用语义恰当的标签,使页面有良好的结构,页面元素有含义,能够让人和搜索引擎都容易理解。比如使用footer,body,header,section标签等,好处是便于阅读和理解,便于爬虫抓取和搜索引擎优化。
可以理解为一组自定义业务的抽象封装,是根据项目的情况来进行封装组合到一起的,比如我们可以分为登录模块,评论模块。模块可维护性好,组合灵活,方便调用,多人协作互不干扰。因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。
指对具体的某个功能的封装,比如所有的分页可以封装为分页组件来统一使用,以此来达到组件复用,提高开发效率。
概念:指使用软件工程的技术和方法来进行前端项目的开发、维护和管理。
前端工程化包含如下:
1.代码规范: 保证团队所有成员以同样的规范开发代码。
2.分支管理: 不同的开发人员开发不同的功能或组件,按照统一的流程合并到主干。
3.模块管理: 一方面,团队引用的模块应该是规范的;另一方面,必须保证这些模块可以正确的加入到最终编译好的包文件中。(以上两点可以总结为模块化或者组件化开发。)
4.自动化测试:为了保证和并进主干的代码达到质量标准,必须有测试,而且测试应该是自动化的,可以回归的。
5.构建:主干更新以后,自动将代码编译为最终的目标格式,并且准备好各种静态资源,
6.部署。 将构建好的代码部署到生产环境。
spa(single page web application)单页面应用,就是只有一个Web页面的应用,浏览器一开始会加载所需要的HTML、CSS和js资源,所有的操作通过js来动态更新该页面,这样的程序就叫做spa单页面应用。
优点:
1.用户体验好,避免不必要的跳转页面和重复渲染。
2.减轻服务器端压力。
3.前后端分离,各司其责,便于优化管理。
缺点:
1.不利于seo搜索优化。(可以通过ssr服务器端渲染等方法)
2.首屏加载时间过长。
就是在服务器端生成页面的html,再发送到浏览器。与单页面应用相比,服务器端渲染更好的利于seo搜索优化,和减少首页加载时间。但是同时也存在缺点,比如学习成本比较大,也会加大服务器的压力。
http协议(Hyper Text Transfer Protocol超文本传输协议),是一个应用层的协议。
1.支持客户端/服务器模式,也就是请求/响应的模式。
2.简单快速:是说我们只需要指定get,post,head这些请求方式和访问路径,就可以进行访问了。
3.灵活:是指现在的版本中可以传输任意的数据,文件,xml,json都可以,只需要指定content-type对应的类型即可。
4.无连接:是指每次链接只处理一个请求,服务器处理完请求后,响应给客户端并收到客户的应答后就断开链接。
5.无状态:是说http协议对事务的处理没有记忆能力,如果中断了,就必须要重新传输了。
http有4个版本,http/0.9,http/1.0,http/1.1,http/2.0。
1.http/0.9:在1991年发布,是http协议最初的版本,功能简陋,只支持get的请求方式,也不支持请求头,服务器只能返回html格式的字符串。
缺点:功能比较简陋,只能处理get请求,返回类型比较少。
2.http/1.0:在1996年发布,比0.9支持了很多的内容;
①支持get,post,head请求
②支持请求头和响应头,状态码,缓存,内容编码。
③服务器响应对象不仅限于超文本了,content-type可以设置更多的格式,图片,视频等。
④新建一个tcp连接,只能发送一个请求,服务器也只能处理一个请求。
⑤部分浏览器支持connection:keep-alive;长连接,可以在请求结束后服务器不关闭连接。
缺点:tcp连接新建需要三次握手,每个tcp连接只能发送一个请求,而且发送后服务器就会断开此次连接,这样的处理比较耗费效率,也没办法复用。虽然也有一些浏览器实现了Connection:keep-alive;长连接,但是并不是每个浏览器都支持这个。
3.http/1.1:在1997年发布,添加了很多优化性的内容;
①支持持久连接,不用声明Connection: keep-alive;tcp新建连接后默认不关闭,可以被对个请求复用。客户端也可以主动在最后一个请求发送Connection:close;来关闭连接。
②支持在一个tcp连接里,支持客户端可以同时请求多个连接,但是服务器还是需要按照顺序来处理,谁先发送的就先处理谁。
③新增了多个请求的方法,options,put,delete,connect,trace。
④新增了一些状态码,身份认证机制,支持文件断点续传。
⑤添加了一些cache的新特性,增加Cache-control属性。
缺点:虽然支持多个请求,但是在服务器端需要排队处理,会出现请求堵塞的情况。消息头部无法压缩,比较占字节,会浪费一些网络资源。
4.http/2.0:在2015年发布,在谷歌,ie11以及火狐等现代浏览器已经可以支持http/2.0协议了;
①二进制协议,在http1.1里是超文本传输协议,http2.0已经可以支持二进制协议了,体积更小,易于解析不会出错。
②真正的多请求处理,客户端请求多个到服务器端,在服务器端处理是可以多对多的,也不用服务器按照请求的顺序去处理,即使某个请求堵塞了也不会影响到其他的请求处理。
③解决了http1.1的请求头部压缩问题,加快请求传输速度。
④服务器推送,服务器可以主动向客户端推送资源,资源包括页面,css,js,图片等资源,客户端检测到后解析处理,这样这些资源已经在本地了,浏览器可以更快的拿到而不是再通过网络重新请求,这样减少了客户端去请求服务器再到服务器响应的过程,大大提高了效率和资源的利用。
1.https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2.http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3.http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4.http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
注:ssl是一个位于tcp和http之间的安全协议,为数据通讯提供安全支持
301 redirect: 301 代表永久性转移(Permanently Moved)
302 redirect: 302 代表暂时性转移(Temporarily Moved )
etag是entity tag的缩写,意思就是实体标签的意思,它是http协议中请求head中的一个属性,用来帮助服务器控制web端的缓存验证。
①TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
②TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
③UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
④每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
⑤TCP对系统资源要求较多,UDP对系统资源要求较少。
get和post的区别?
1.get用于获取数据,post是提交数据。
2.get提交的参数追加在url的后面,用?和&来连接,post的参数放在Request Body提交。
3.get的url会有长度限制,最多2K,post则不会限制数据大小,而且还可以设置提交的数据类型(文件,json这些)。
4.get是不安全的,因为url上参数都已经暴露了,post是安全的。
5.get的请求参数会被保存在浏览历史记录里,post则没有。
6.get请求可以被浏览器缓存,post则没有。
1.当我们输入某个地址后,首先需要dns域名解析这个地址,根据一系列的dns解析域名的步骤找到对应服务器的ip。
2.tcp的三次握手建立连接。
3.建立tcp的链接后发送http请求的报文,包括请求行,消息报头,请求正文这些。
4.http响应报文,包括状态行,消息报头,响应正文,浏览器得到html代码。
5.最后浏览器解析得到的html,将结果呈现给用户。
1.Trident: 主要是IE,一些双核浏览器也会用到,比如360浏览器,腾讯浏览器,百度浏览器
2.Gecko:现在主要有火狐
3.Webkit:苹果自主研发的内核,使用的浏览器相当多,比如safari,Google chrome,opera,以及360,腾讯这些浏览器的高速模式都是用的这个。
4.Blink:基于webkit,Google与Opera共同开发,现在google在用。
1.解析html生成dom树
2.解析css生成cssom规则树
3.将dom树和cssom规则树合并在一起生成render渲染树
4.遍历render渲染树的节点开始布局,计算每个节点的位置大小信息。
5.将render渲染树每个节点绘制到页面来显示。
注意:渲染的时候回出现阻塞的情况,当浏览器碰到script标记时候,dom构建将暂停,直到脚本执行完毕,所以要把脚本放到最下面,避免阻塞。css的话要放在最上面。
重绘:当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如添加个背景色,设置个文字颜色,则就叫称为重绘。
回流:当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。
回流何时发生:
当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:
1、添加或者删除可见的DOM元素;
2、元素位置改变;
3、元素尺寸改变——边距、填充、边框、宽度和高度
4、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
5、页面渲染初始化;
6、浏览器窗口尺寸改变——resize事件发生时;
注意:回流必定触发重绘,重绘不一定触发回流,重绘的开销比较小,回流的代价比较高。