整理了一张前端面试思惟导图我放在了文章最后面,因为图片太大,建议下载查看。javascript
本文整理了面试大体思路以及一些基础知识点,但愿能给你带去些许帮助,助力你找到心仪的好工做。css
注意点(克服紧张,语速放慢,目光直视面试官)html
面试官下午好,我叫**,今天来应聘贵公司的前端工程师岗位。我从事前端开发两年多,有X年多的Vue开发经验,一年React开发经验,在上家公司主要从事H5页面,后台管理系统,混合App等项目开发。日常喜欢逛一些技术社区丰富本身的技术,像思否,掘金之类,而且本身也独立开发了我的博客网站,记录本身的工做总结和学习心得。 个人性格比较温和,跟同事朋友相处时比较外向,在工做中代码开发时我喜欢全心全意的投入,对于工做我总抱着认真负责的态度。面试官,以上是个人介绍,谢谢。前端
这部分大几率会问,注意语言措辞,作好充足的准备没你就不会慌张,安全感是本身给本身的。 示例:vue
项目简介:XXAPP是一款多功能的民营银行软件,主要有帐户交易、转帐汇款、存单产品买入卖出、充值提现等功能,使用原生内嵌webview的方式,通讯方面iOS采用messageHandlers[fn].postMessage(data)
方法。Android
采用window.AndroidWebView[fn] (data)
html5
项目亮点及难点:登陆超时从新登陆后继续返回原先操做的页面。java
语义化意味着顾名思义,HTML5的语义化指的是合理正确的使用语义化的标签来建立页面结构,如
header,footer,nav,从标签上便可以直观的知道这个标签的做用,而不是滥用div。
语义化的优势有:
代码结构清晰,易于阅读,利于开发和维护
方便其余设备解析(如屏幕阅读器)根据语义渲染网页。
有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不一样的标签来赋予不一样的权重
复制代码
网页生成过程:node
HTML
被HTML解析器解析成DOM
树css
则被css解析器解析成CSSOM
树DOM
树和CSSOM
树,生成一棵渲染树(Render Tree
)flow
),即将全部渲染树的全部节点进行平面合成paint
)在屏幕上重排(也称回流): 当DOM
的变化影响了元素的几何信息(DOM
对象的位置和尺寸大小),浏览器须要从新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫作重排。 触发:react
重绘: 当一个元素的外观发生改变,但没有改变布局,从新把元素外观绘制出来的过程,叫作重绘。 触发:webpack
color、background、box-shadow
等属性重排优化建议:
DOM
元素position:absolute
或fixed
元素,对其余元素影响不大GPU
加速,translate
使用3D
变化transform
不重绘,不回流 是由于transform
属于合成属性,对合成属性进行transition/animate
动画时,将会建立一个合成层。这使得动画元素在一个独立的层中进行渲染。当元素的内容没有发生改变,就没有必要进行重绘。浏览器会经过从新复合来建立动画帧。
全部HTML
元素能够看做盒子,在CSS中,"box model"
这一术语是用来设计和布局时使用。 CSS
盒模型本质上是一个盒子,封装周围的HTML
元素,它包括:边距,边框,填充,和实际内容。 盒模型容许咱们在其它元素和周围元素边框之间的空间放置元素。
!important>style>id>class
BFC
是 Block Formatting Context
的缩写,即块格式化上下文。BFC
是CSS布局的一个概念,是一个环境,里面的元素不会影响外面的元素。 布局规则:Box是CSS布局的对象和基本单位,页面是由若干个Box组成的。元素的类型和display属性,决定了这个Box的类型。不一样类型的Box会参与不一样的Formatting Context
。 建立:浮动元素 display:inline-block position:absolute
应用: 1.分属于不一样的BFC
时,能够防止margin
重叠 2.清除内部浮动 3.自适应多栏布局
BOM(Browser Object Model)
是指浏览器对象模型,能够对浏览器窗口进行访问和操做。使用 BOM,开发者能够移动窗口、改变状态栏中的文本以及执行其余与页面内容不直接相关的动做。 使 JavaScript
有能力与浏览器"对话"。 DOM (Document Object Model)
是指文档对象模型,经过它,能够访问HTML
文档的全部元素。 DOM
是 W3C
(万维网联盟)的标准。DOM
定义了访问 HTML
和 XML
文档的标准: "W3C 文档对象模型(DOM)是中立于平台和语言的接口,它容许程序和脚本动态地访问和更新文档的内容、结构和样式。" W3C DOM
标准被分为 3 个不一样的部分:
DOM
- 针对任何结构化文档的标准模型XML DOM
- 针对 XML 文档的标准模型HTML DOM
- 针对 HTML 文档的标准模型什么是 XML DOM
? XML DOM
定义了全部 XML 元素的对象和属性,以及访问它们的方法。 什么是 HTML DOM? HTML DOM 定义了全部 HTML 元素的对象和属性,以及访问它们的方法。
string、number、boolean、null、undefined、object(function、array)、symbol(ES10 BigInt)
typeof
主要用来判断数据类型 返回值有string、boolean、number、function、object、undefined。
instanceof
判断该对象是谁的实例。null
表示空对象 undefined
表示已在做用域中声明但未赋值的变量闭包是指有权访问另外一个函数做用域中的变量的函数 ——《JavaScript高级程序设计》
当函数能够记住并访问所在的词法做用域时,就产生了闭包,
即便函数是在当前词法做用域以外执行 ——《你不知道的JavaScript》
原型: 对象中固有的__proto__
属性,该属性指向对象的prototype
原型属性。
原型链: 当咱们访问一个对象的属性时,若是这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有本身的原型,因而就这样一直找下去,也就是原型链的概念。原型链的尽头通常来讲都是Object.prototype
因此这就是咱们新建的对象为何可以使用toString()
等方法的缘由。
特色: JavaScript
对象是经过引用来传递的,咱们建立的每一个新对象实体中并无一份属于本身的原型副本。当咱们修改原型时,与之相关的对象也会继承这一改变。
this
对象是是执行上下文中的一个属性,它指向最后一次调用这个方法的对象,在全局函数中,this
等于window
,而当函数被做为某个对象调用时,this等于那个对象。 在实际开发中,this
的指向能够经过四种调用模式来判断。
this
指向全局对象。this
指向这个对象。this
指向这个用new
新建立的对象。apply 、 call 和 bind
调用模式,这三个方法均可以显示的指定调用函数的 this 指向。apply
接收参数的是数组,call
接受参数列表,`` bind方法经过传入一个对象,返回一个
this 绑定了传入对象的新函数。这个函数的
this指向除了使用
new `时会被改变,其余状况下都不会改变。new
prototype
对象。this
指向这个对象,执行构造函数的代码(为这个新对象添加属性)做用域
负责收集和维护由全部声明的标识符(变量)组成的一系列查询,并实施一套很是严格的规则,肯定当前执行的代码对这些标识符的访问权限。(全局做用域、函数做用域、块级做用域)。 做用域链就是从当前做用域开始一层一层向上寻找某个变量,直到找到全局做用域仍是没找到,就宣布放弃。这种一层一层的关系,就是做用域链
。
(1)第一种是以原型链的方式来实现继承
,可是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被全部的实例对象所共享,容易形成修改的混乱。还有就是在建立子类型的时候不能向超类型传递参数。
(2)第二种方式是使用借用构造函数
的方式,这种方式是经过在子类型的函数中调用超类型的构造函数来实现的,这一种方法解决了不能向超类型传递参数的缺点,可是它存在的一个问题就是没法实现函数方法的复用,而且超类型原型定义的方法子类型也没有办法访问到。
(3)第三种方式是组合继承
,组合继承是将原型链和借用构造函数组合起来使用的一种方式。经过借用构造函数的方式来实现类型的属性的继承,经过将子类型的原型设置为超类型的实例来实现方法的继承。这种方式解决了上面的两种模式单独使用时的问题,可是因为咱们是以超类型的实例来做为子类型的原型,因此调用了两次超类的构造函数,形成了子类型的原型中多了不少没必要要的属性。
(4)第四种方式是原型式继承
,原型式继承的主要思路就是基于已有的对象来建立新的对象,实现的原理是,向函数中传入一个对象,而后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的 Object.create() 方法就是原型式继承的实现。缺点与原型链方式相同。
(5)第五种方式是寄生式继承
,寄生式继承的思路是建立一个用于封装继承过程的函数,经过传入一个对象,而后复制一个对象的副本,而后对象进行扩展,最后返回这个对象。这个扩展的过程就能够理解是一种继承。这种继承的优势就是对一个简单对象实现继承,若是这个对象不是咱们的自定义类型时。缺点是没有办法实现函数的复用。
(6)第六种方式是寄生式组合继承
,组合继承的缺点就是使用超类型的实例作为子类型的原型,致使添加了没必要要的原型属性。寄生式组合继承的方式是使用超类型的原型的副原本做为子类型的原型,这样就避免了建立没必要要的属性。
JS
是单线程的,为了防止一个函数执行时间过长阻塞后面的代码,因此会先将同步代码压入执行栈中,依次执行,将异步代码推入异步队列,异步队列又分为宏任务队列和微任务队列,由于宏任务队列的执行时间较长,因此微任务队列要优先于宏任务队列。微任务队列的表明就是,Promise.then
,MutationObserver
,宏任务的话就是setImmediate setTimeout setInterval
ajax是一种异步通讯的方法,从服务端获取数据,达到局部刷新页面的效果。 过程:
XMLHttpRequest
对象;open
方法传入三个参数 请求方式(GET/POST)、url、同步异步(true/false)
;onreadystatechange
事件,当readystate
等于4时返回responseText
;event.stopPropagation()
或者 ie下的方法 event.cancelBubble = true;
//阻止事件冒泡
${data}
);MVVM是Model-View-ViewModel
缩写,也就是把MVC
中的Controller
演变成ViewModel。Model
层表明数据模型,View
表明UI组件,ViewModel
是View
和Model
层的桥梁,数据会绑定到viewModel
层并自动将数据渲染到页面中,视图变化的时候会通知viewModel
层更新数据。
每一个Vue
实例在建立时都会通过一系列的初始化过程,vue
的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的就是为了完成一些动做或者事件
create阶段
:vue实例被建立 beforeCreate
: 建立前,此时data和methods中的数据都尚未初始化 created
: 建立完毕,data中有值,未挂载mount阶段
: vue实例被挂载到真实DOM节点 beforeMount
:能够发起服务端请求,去数据 mounted
: 此时能够操做Domupdate阶段
:当vue实例里面的data数据变化时,触发组件的从新渲染 beforeUpdate
updated
destroy阶段
:vue实例被销毁 beforeDestroy
:实例被销毁前,此时能够手动销毁一些方法 destroyed
computed与watch
watch 属性监听 是一个对象,键是须要观察的属性,值是对应回调函数,主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操做,监听属性的变化,须要在数据变化时执行异步或开销较大的操做时使用
computed 计算属性 属性的结果会被缓存,当computed
中的函数所依赖的属性没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取。除非依赖的响应式属性变化时才会从新计算,主要当作属性来使用 computed
中的函数必须用return
返回最终的结果 computed
更高效,优先使用
使用场景 computed
:当一个属性受多个属性影响的时候使用,例:购物车商品结算功能 watch
:当一条数据影响多条数据的时候使用,例:搜索数据
key
的做用主要是为了更高效的对比虚拟DOM中每一个节点是不是相同节点;Vue在patch
过程当中判断两个节点是不是相同节点,key是一个必要条件,渲染一组列表时,key每每是惟一标识,因此若是不定义key的话,Vue
只能认为比较的两个节点是同一个,哪怕它们实际上不是,这致使了频繁更新元素,使得整个patch
过程比较低效,影响性能;undefined
,则可能永 远认为这是两个相同的节点,只能去作更新操做,这形成了大量的dom更新操做,明显是不可取的。父->子props
,子->父 $on、$emit` 获取父子组件实例
children
Ref 获取实例的方式调用组件的属性或者方法
Provide、inject` 官方不推荐使用,可是写组件库时很经常使用
Event Bus
实现跨组件通讯 Vue.prototype.$bus = new Vue() Vuex
$attrs、$listeners
Provide、inject
当一个Vue实例建立时,Vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter而且在内部追踪相关依赖,在属性被访问和修改时通知变化。每一个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程当中把属性记录为依赖,以后当依赖项的 setter 被调用时,会通知 watcher从新计算,从而导致它关联的组件得以更新。
vue
中双向绑定是一个指令v-model
,能够绑定一个动态值到视图,同时视图中变化能改变该值。v-model
是语法糖,默认状况下相于:value和@input
。v-model
能够减小大量繁琐的事件处理代码,提升开发效率,代码可读性也更好v-model
v-model
,自定义组件上若是要使用它须要在组件内绑定value并处理输入事件v-model
模板的组件渲染函数,发现它会被转换为value属性的绑定以及一个事件监听,事件回调函数中会作相应变量更新操做,这说明神奇魔法其实是vue的编译器完成的。nextTick
是Vue
提供的一个全局API
,是在下次DOM
更新循环结束以后执行延迟回调,在修改数据以后使用$nextTick
,则能够在回调中获取更新后的DOM
;Vue
将开启1个队列,并缓冲在同一事件循环中发生的全部数据变动。若是同一个watcher
被屡次触发,只会被推入到队列中-次。这种在缓冲时去除重复数据对于避免没必要要的计算和DOM
操做是很是重要的。nextTick
方法会在队列中加入一个回调函数,确保该函数在前面的dom操做完成后才调用;nextTick
实现,它会在callbacks
里面加入咱们传入的函数,而后用timerFunc
异步方式调用它们,首选的异步方式会是Promise
。这让我明白了为何能够在nextTick
中看到dom
操做结果。vnode 虚拟DOM节点 建立:
export function Vnode (){
return {
tag:'div',
children: 'span',
attr:'',
text:'你好!'
}
}
复制代码
initProxy
:做用域代理,拦截组件内访问其它组件的数据。initLifecycle
:创建父子组件关系,在当前组件实例上添加一些属性和生命周期标识。如[Math Processing Error]parent,parent,refs,$children,_isMounted
等。initEvents
:对父组件传入的事件添加监听,事件是谁建立谁监听,子组件建立事件子组件监听initRender
:声明[Math Processing Error]slots和slots和createElement()等。initInjections
:注入数据,初始化inject,通常用于组件更深层次之间的通讯。initState
:重要)数据响应式:初始化状态。不少选项初始化的汇总:data,methods,props,computed和watch。initProvide
:提供数据注入。思考:为何先注入再提供呢??
答:一、首先来自祖辈的数据要和当前实例的data,等判重,相结合,因此注入数据的initInjections必定要在InitState
的上面。2. 从上面注入进来的东西在当前组件中转了一下又提供给后代了,因此注入数据也必定要在上面。
vm.[Math Processing Error]mount(vm.mount(vm.options.el)
:挂载实例。
做用:实现组件缓存
`activated `组件渲染后调用
`deactivated `组件销毁后调用
复制代码
原理:Vue.js
内部将DOM
节点抽象成了一个个的VNode
节点,keep-alive
组件的缓存也是基于VNode
节点的而不是直接存储DOM
结构。它将知足条件(pruneCache与pruneCache)
的组件在cache
对象中缓存起来,在须要从新渲染的时候再将vnode
节点从cache
对象中取出并渲染。
include
字符串或正则表达式。只有名称匹配的组件会被缓存
exclude
字符串或正则表达式。任何名称匹配的组件都不会被缓存
max
数字、最多能够缓存多少组件实例
vuex
是一个专门为vue.js应用程序开发的状态管理库。 核心概念:
state
(单一状态树) getter/Mutation
显示提交更改state
Action相似Mutation
,提交Mutation
,能够包含任意异步操做。module
(当应用变得庞大复杂,拆分store
为具体的module
模块)在js中,渲染真实DOM
的开销是很是大的, 好比咱们修改了某个数据,若是直接渲染到真实DOM
, 会引发整个dom
树的重绘和重排。那么有没有可能实现只更新咱们修改的那一小块dom而不要更新整个dom
呢?此时咱们就须要先根据真实dom
生成虚拟dom
, 当虚拟dom
某个节点的数据改变后会生成有一个新的Vnode
, 而后新的Vnode
和旧的Vnode
做比较,发现有不同的地方就直接修改在真实DOM上,而后使旧的Vnode
的值为新的Vnode
。
diff的过程就是调用patch
函数,比较新旧节点,一边比较一边给真实的DOM
打补丁。在采起diff
算法比较新旧节点的时候,比较只会在同层级进行。 在patch
方法中,首先进行树级别的比较 new Vnode
不存在就删除 old Vnode
old Vnode
不存在就增长新的Vnode
都存在就执行diff更新 当肯定须要执行diff算法时,比较两个Vnode
,包括三种类型操做:属性更新,文本更新,子节点更新 新老节点均有子节点,则对子节点进行diff
操做,调用updatechidren
若是老节点没有子节点而新节点有子节点,先清空老节点的文本内容,而后为其新增子节点 若是新节点没有子节点,而老节点有子节点的时候,则移除该节点的全部子节点 老新老节点都没有子节点的时候,进行文本的替换
updateChildren 将Vnode
的子节点Vch和oldVnode的子节点oldCh提取出来。 oldCh和vCh
各有两个头尾的变量StartIdx和EndIdx
,它们的2个变量相互比较,一共有4种比较方式。若是4种比较都没匹配,若是设置了key
,就会用key
进行比较,在比较的过程当中,变量会往中间靠,一旦StartIdx>EndIdx
代表oldCh和vCh
至少有一个已经遍历完了,就会结束比较。
编码阶段
尽可能减小data中的数据,data中的数据都会增长getter和setter,会收集对应的watcher
v-if和v-for不能连用
若是须要使用v-for给每项元素绑定事件时使用事件代理
SPA 页面采用keep-alive缓存组件
在更多的状况下,使用v-if替代v-show
key保证惟一
使用路由懒加载、异步组件
防抖、节流
第三方模块按需导入
长列表滚动到可视区域动态加载
图片懒加载
SEO优化
预渲染
服务端渲染SSR
打包优化
压缩代码
Tree Shaking/Scope Hoisting
使用cdn加载第三方模块
多线程打包happypack
splitChunks抽离公共文件
sourceMap优化
用户体验
骨架屏
PWA
还可使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。
复制代码
更小巧、更快速 支持自定义渲染器 支持摇树优化:一种在打包时去除无用代码的优化手段 支持Fragments和跨组件渲染
模板语法99%保持不变 原生支持基于class的组件,而且无需借助任何编译及各类stage阶段的特性 在设计时也考虑TypeScript的类型推断特性 重写虚拟DOM
能够期待更多的编译时提示来减小运行时的开销 优化插槽生成
能够单独渲染父组件和子组件 静态树提高
下降渲染成本 基于Proxy的观察者机制
节省内存开销
检测机制
更加全面、精准、高效,更具可调试式的响应跟踪
Keys是React用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。
复制代码
虚拟DOM
本质上是JavaScript
对象,是对真实DOM
的抽象表现。 状态变动时,记录新树和旧树的差别 最后把差别更新到真正的dom
中 render函数:
tagName
生成父标签,读取props
,设置属性,若是有content
,设置innerHtml或innerText
,render
方法,将生成的子元素依次添加到父元素中,并返回根元素。Props
,子->父用callback
回调Event
模块Redux、Mobx
等全局状态管理管库Context Api context
会使组件复用性变差Context
提供了一个无需为每层组件手动添加 props
,就能在组件树间进行数据传递的方法.若是你只是想避免层层传递一些属性,组件组合(component composition
)有时候是一个比 context 更好的解决方案。 5. 组件组合缺点:会使高层组件变得复杂
调用React.createElement函数建立对象
复制代码
componentWillMount、componentWillReceiveProps、componentWillUpdate在16版本被废弃,在17版本将被删除,须要使用UNSAVE_前缀使用,目的是向下兼容。
使用return null而不是CSS的display:none来控制节点的显示隐藏。保证同一时间页面的DOM节点尽量的少。
不要使用数组下标做为key 利用 shouldComponentUpdate
和 PureComponent
避免过多 render function
; render
里面尽可能减小新建变量和bind函数,传递参数是尽可能减小传递参数的数量。 尽可能将 props
和 state
扁平化,只传递 component
须要的 props
(传得太多,或者层次传得太深,都会加剧shouldComponentUpdate
里面的数据比较负担),慎将 component
看成 props
传入
使用 babel-plugin-import
优化业务组件的引入,实现按需加载 使用 SplitChunksPlugin
拆分公共代码 使用动态 import
,懒加载 React
组件
bind/箭头函数
复制代码
React Fiber 是一种基于浏览器的单线程调度算法.
复制代码
setState
只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。setState
的“异步”并非说内部由异步代码实现,其实自己执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新以前,致使在合成事件和钩子函数中无法立马拿到更新后的值,形式了所谓的“异步”,固然能够经过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。setState
的批量更新优化也是创建在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中若是对同一个值进行屡次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,若是是同时 setState 多个不一样的值,在更新时会对其进行合并批量更新。Redux的实现流程
用户页面行为触发一个Action
,而后Store
调用Reducer
,而且传入两个参数:当前State
和收到的Action
。Reducer
会返回新的State
。每当state
更新以后,view
会根据state
触发从新渲染。
React-Redux:
Provider
:从最外部封装了整个应用,并向connect
模块传递store
。 Connect
:
state
和action
经过props
的方式传入到原组件内部。store tree
变化,使其包装的原组件能够响应state
变化高阶组件是参数为组件,返回值为新组件的函数。HOC
是纯函数,没有反作用。HOC
在React
的第三方库中很常见,例如Redux
的connect
组件。
高阶组件的做用:
bootstrap
)代码State
抽象和更改Props
更改React
组件?React.createClass()、ES6 class
和无状态函数
React
元素与组件的区别?组件是由元素构成的。元素数据结构是普通对象,而组件数据结构是类或纯函数。
数据流:
react主张函数式编程,因此推崇纯组件,数据不可变,单向数据流,
vue的思想是响应式的,也就是基因而数据可变的,经过对每个属性创建Watcher来监听,当属性变化的时候,响应式的更新对应的虚拟dom。
监听数据变化实现原理:
Vue
经过 getter/setter
以及一些函数的劫持,能精确知道数据变化,不须要特别的优化就能达到很好的性能React
默认是经过比较引用的方式进行的,若是不优化(PureComponent/shouldComponentUpdate
)可能致使大量没必要要的VDOM的从新渲染。组件通讯的区别:jsx和.vue模板。
HoC和Mixins
(在Vue中咱们组合不一样功能的方式是经过Mixin
,而在React
中咱们经过HoC
(高阶组件))。性能优化
React: shouldComponentUpdate
Vue
:内部实现shouldComponentUpdate
的优化,因为依赖追踪系统存在,经过watcher
判断是否须要从新渲染(当一个页面数据量较大时,Vue
的性能较差,形成页面卡顿,因此通常数据比较大的项目倾向使用React
)。从实现原理上来讲,最大的区别是两点:
Redux使用的是不可变数据,而Vuex
的数据是可变的。Redux
每次都是用新的state
替换旧的state
,而Vuex
是直接修改
Redux在检测数据变化的时候,是经过diff
的方式比较差别的,而Vuex
其实和Vue的原理同样,是经过 getter/setter
来比较的(若是看Vuex
源码会知道,其实他内部直接建立一个Vue
实例用来跟踪数据变化)
三个方面:
网络篇:
构建请求
查找强缓存
DNS解析
创建TCP链接(三次握手)
发送HTTP请求(网络请求后网络响应)
浏览器解析篇:
解析html构建DOM树
解析css构建CSS树、样式计算
生成布局树(Layout Tree)
浏览器渲染篇:
创建图层树(Layer Tree)
生成绘制列表
生成图块并栅格化
显示器显示内容
最后断开链接:TCP 四次挥手
(浏览器会将各层的信息发送给GPU,GPU会将各层合成,显示在屏幕上)
复制代码
1.`TCP`向上层提供面向链接的可靠服务 ,`UDP`向上层提供无链接不可靠服务。
2.虽然 `UDP` 并无 `TCP` 传输来的准确,可是也能在不少实时性要求高的地方有所做为
3.对数据准确性要求高,速度能够相对较慢的,能够选用`TCP`
复制代码
区别 | UDP | TCP |
---|---|---|
是否链接 | 无链接 | 面向链接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
链接对象个数 | 支持一对一,一对多,多对一和多对多交互通讯 | 只能是一对一通讯 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
1.`HTTP` 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
2.`HTTP` 是不安全的,而 HTTPS 是安全的
3.`HTTP` 标准端口是80 ,而 HTTPS 的标准端口是443
4.`在OSI` 网络模型中,HTTP工做于应用层,而HTTPS 的安全传输机制工做在传输层
5.`HTTP` 没法加密,而HTTPS 对传输的数据进行加密
6.`HTTP`无需证书,而HTTPS 须要CA机构wosign的颁发的SSL证书
复制代码
1.GET在浏览器回退不会再次请求,POST会再次提交请求
2.GET请求会被浏览器主动缓存,POST不会,要手动设置
3.GET请求参数会被完整保留在浏览器历史记录里,POST中的参数不会
4.GET请求在URL中传送的参数是有长度限制的,而POST没有限制
5.GET参数经过URL传递,POST放在Request body中
6.GET参数暴露在地址栏不安全,POST放在报文内部更安全
7.GET通常用于查询信息,POST通常用于提交某种信息进行某些修改操做
8.GET产生一个TCP数据包;POST产生两个TCP数据包
复制代码
XSS
(Cross-Site Scripting
,跨站脚本攻击)是一种代码注入攻击。攻击者在目标网站上注入恶意代码,当被攻击者登录网站时就会执行这些恶意代码,这些脚本能够读取 cookie,session tokens
,或者其它敏感的网站信息,对用户进行钓鱼欺诈,甚至发起蠕虫攻击等。
CSRF
(Cross-site request forgery
)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕事后台的用户验证,达到冒充用户对被攻击的网站执行某项操做的目的。
XSS避免方式:
url
参数使用encodeURIComponent
方法转义InnerHtml
插入HTML
内容CSRF
避免方式:
DDoS
又叫分布式拒绝服务,全称 Distributed Denial of Service
,其原理就是利用大量的请求形成资源过载,致使服务不可用。
DDos
避免方式:
ICMP
包等好比:
200响应成功
301永久重定向
302临时重定向
304资源缓存
403服务器禁止访问
404服务器资源未找到
500 502服务器内部错误
504 服务器繁忙
1xx Informational(信息状态码) 接受请求正在处理
2xx Success(成功状态码) 请求正常处理完毕
3xx Redirection(重定向状态码) 须要附加操做已完成请求
4xx Client Error(客户端错误状态码) 服务器没法处理请求
5xx Server Error(服务器错误状态码) 服务器处理请求出错
复制代码
刚开始双方都处于 establised
状态,假如是客户端先发起关闭请求,则:
创建TCP链接->发送请求行->发送请求头->(到达服务器)发送状态行->发送响应头->发送响应数据->断TCP链接
1. 浏览器缓存
2. 防抖、节流
3. 资源懒加载、预加载
4.开启Nginx gzip压缩
三个方面来讲明前端性能优化
一: webapck优化与开启gzip压缩
1.babel-loader用 include 或 exclude 来帮咱们避免没必要要的转译,不转译node_moudules中的js文件
其次在缓存当前转译的js文件,设置loader: 'babel-loader?cacheDirectory=true'
2.文件采用按需加载等等
3.具体的作法很是简单,只须要你在你的 request headers 中加上这么一句:
accept-encoding:gzip
4.图片优化,采用svg图片或者字体图标
5.浏览器缓存机制,它又分为强缓存和协商缓存
二:本地存储——从 Cookie 到 Web Storage、IndexedDB
说明一下SessionStorage和localStorage还有cookie的区别和优缺点
三:代码优化
1.事件代理
2.事件的节流和防抖
3.页面的回流和重绘
4.EventLoop事件循环机制
5.代码优化等等
复制代码
一个域下的js脚本未经容许的状况下,不能访问另外一个域下的内容。一般判断跨域的依据是协议、域名、端口号是否相同,不一样则跨域。同源策略是对js脚本的一种限制,并非对浏览器的限制,像img,script脚本请求不会有跨域限制。
Ajax : 短链接
Websocket : 长链接,双向的。
Form表单(最原始的)
复制代码
解决方案:
jsonp
(利用script
标签没有跨域限制的漏洞实现。缺点:只支持GET
请求)CORS
(设置Access-Control-Allow-Origin
:指定可访问资源的域名)postMessage
(message, targetOrigin, [transfer]
)(HTML5
新增API 用于多窗口消息、页面内嵌iframe消息传递),经过onmessage
监听 传递过来的数据Websocket
是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通讯,同时也是跨域的一种解决方案。Node
中间件代理Nginx
反向代理iframe
的方式,不经常使用。浏览器的本地存储主要分为Cookie、WebStorage和IndexDB
, 其中WebStorage
又能够分为localStorage和sessionStorage
。
共同点: 都是保存在浏览器端、且同源的
不一样点:
cookie
数据始终在同源的http
请求中携带(即便不须要),即cookie
在浏览器和服务器间来回传递。cookie
数据还有路径(path
)的概念,能够限制cookie
只属于某个路径下sessionStorage
和localStorage
不会自动把数据发送给服务器,仅在本地保存。cookie
数据不能超过4K,sessionStorage和localStorage
能够达到5MsessionStorage
:仅在当前浏览器窗口关闭以前有效;localStorage
:始终有效,窗口或浏览器关闭也一直保存,本地存储,所以用做持久数据;cookie
:只在设置的cookie
过时时间以前有效,即便窗口关闭或浏览器关闭sessionStorage
:不在不一样的浏览器窗口中共享,即便是同一个页面;localstorage
:在全部同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在cookie
: 也是在全部同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在module.exports={
entry: {},
output: {},
plugins: [],
module: [rules:[{}]]
}
复制代码
入口起点
:使用 entry
配置手动地分离代码。防止重复
:使用 CommonsChunkPlugin
去重和分离 chunk
。动态导入
:经过模块的内联函数调用来分离代码。loader
: 是一个导出为函数的javascript
模块,根据rule
匹配文件扩展名,处理文件的转换器。
file-loader
:把文件输出到一个文件夹中,在代码中经过相对 URL
去引用输出的文件 (处理图片和字体)
url-loader
: 与file-loader
相似,区别是用户能够设置一个阈值,大于阈值会交给file-loader
处理,小于阈值时返回文件base64
形式编码 (处理图片和字体)
image-loader
:加载而且压缩图片文件
babel-loader
:把 ES6
转换成 ES5
sass-loader
:将SCSS/SASS
代码转换成CSS
css-loader
:加载 CSS
,支持模块化、压缩、文件导入等特性
style-loader
:把 CSS
代码注入到 JavaScript
中,经过 DOM
操做去加载 CSS
postcss-loader
:扩展 CSS
语法,使用下一代 CSS
,能够配合 autoprefixer
插件自动补齐 CSS3 前缀 eslint-loader
:经过 ESLint
检查 JavaScript
代码
plugin:本质是插件,基于事件流框架 Tapable
,插件能够扩展 Webpack
的功能,在 Webpack
运行的生命周期中会广播出许多事件,Plugin
能够监听这些事件,在合适的时机经过 Webpack
提供的 API
改变输出结果。
html-webpack-plugin
:简化 HTML
文件建立 (依赖于 html-loader
)
uglifyjs-webpack-plugin
:压缩js文件
clean-webpack-plugin
:目录清除
mini-css-extract-plugin
:分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin
)
Loader
在 module.rules
中配置,做为模块的解析规则,类型为数组。每一项都是一个 Object
,内部包含了 test(类型文件)、loader、options
(参数)等属性。Plugin
在 plugins
中单独配置,类型为数组,每一项是一个Plugin
的实例,参数都经过构造函数传入。CommonJS
是服务器端模块的规范,由Node推广使用,webpack也采用这种规范编写
CommonJS
模块规范主要分为三部分:模块定义、模块标识、模块引用
。
模块定义:module
对象:在每个模块中,module
对象表明该模块自身。 export
属性:module
对象的一个属性,它向外提供接口。输出模块变量的最好方法是使用module.exports
对象。一个单独的文件就是一个模块。每个模块都是一个单独的做用域,也就是说,在该模块内部定义的变量,没法被其余模块读取,除非定义为global
对象的属性。
模块标识:传递给require
方法的参数,必须是符合小驼峰命名的字符串,或者以 . 、.. 、开头的相对路径,或者绝对路径。
模块引用:加载模块使用require
(同步加载),该方法读取一个文件并执行,返回文件内部的module.exports
对象。
在后端,JavaScript
的规范远远落后而且有不少缺陷,这使得难以使用JavaScript
开发大型应用。好比:没有模块系统、标准库较少、没有标准接口、缺少包管理系统、列表内容
CommonJS模块规范很好地解决变量污染问题,每一个模块具备独立空间,互不干扰,命名空间相比之下就不太好。
CommonJS规范定义模块十分简单,接口十分简洁。
CommonJS模块规范支持引入和导出功能,这样能够顺畅地链接各个模块,实现彼此间的依赖关系
CommonJS规范的提出,主要是为了弥补JavaScript没有标准的缺陷,已达到像Python、Ruby和Java那样具有开发大型应用的基础能力,而不是停留在开发浏览器端小脚本程序的阶段
没有并行加载机制
因为CommonJS
是同步加载模块,这对于服务器端是很很差的,由于全部的模块都放在本地硬盘。等待模块时间就是硬盘读取文件时间,很小。可是,对于浏览器而言,它须要从服务器加载模块,涉及到网速,代理等缘由,一旦等待时间过长,浏览器处于”假死”状态。
因此浏览器端不是很适合Common.Js
,出现另外一种规范AMD
AMD
是运行在浏览器环境的一个异步模块定义规范 ,是RequireJS
在推广过程当中对模块定义的规范化产出。
AMD
推崇依赖前置,在定义模块的时候就要声明其依赖的模块
用户体验好,由于没有延迟,依赖模块提早执行了。
CMD
是一个通用模块定义规范;是SeaJs推广过程当中对模块定义的规范化产出
CMD
推崇依赖就近,只有在用到某个模块的时候才会去require
性能好,由于只有用户须要的时候才执行。
防抖节流
函数防抖关注必定时间连续触发,只在最后执行一次,而函数节流侧重于一段时间内只执行一次。
//定义:触发事件后在n秒内函数只能执行一次,若是在n秒内又触发了事件,则会从新计算函数执行时间。
//搜索框搜索输入。只需用户最后一次输入完,再发送请求
//手机号、邮箱验证输入检测 onchange oninput事件
//窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
const debounce = (fn, wait, immediate) => {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
if (immediate && !timer) {
fn.call(this, args);
}
timer = setTimeout(() => {
fn.call(this, args);
}, wait);
};
};
const betterFn = debounce(() => console.log("fn 防抖执行了"), 1000, true);
document.addEventListener("scroll", betterFn);
复制代码
//定义:当持续触发事件时,保证隔间时间触发一次事件。
//1. 懒加载、滚动加载、加载更多或监听滚动条位置;
//2. 百度搜索框,搜索联想功能;
//3. 防止高频点击提交,防止表单重复提交;
function throttle(fn,wait){
let pre = 0;
return function(...args){
let now = Date.now();
if( now - pre >= wait){
fn.apply(this,args);
pre = now;
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
复制代码
//浅拷贝
1. Object.assign(target,source)
2. es6对象扩展运算符。
//深拷贝
function deepClone(obj) {
if (!obj || typeof obj !== "object") return;
let newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key];
}
}
return newObj;
}
复制代码
//数组
const arr = [2,7,5,7,2,8,9];
console.log([...new Set(arr)]); // [2,7,5,8,9];
//对象
const list = [{age:18,name:'张三'},{age:18,name:'李四'},{age:18,name:'王五'}]
let hash = {};
const newArr = arr.reduce((item, next) => {
hash[next.age] ? '' : hash[next.age] = true && item.push(next);
return item;
}, []);
console.log(list);
复制代码
function flatten(arr) {
return arr.reduce((result, item) => {
return result.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
复制代码
它的功能相似于一种标识惟一性的ID,每一个Symbol
实例都是惟一的。 Symbol
类型的key是不能经过Object.keys()
或者for...in
来枚举的, 它未被包含在对象自身的属性名集合(property names
)之中。 因此,利用该特性,咱们能够把一些不须要对外操做和访问的属性使用Symbol来定义。 // 使用Object的API
Object.getOwnPropertySymbols(obj)
// [Symbol(name)]
// 使用新增的反射API Reflect.ownKeys(obj)
// [Symbol(name), 'age', 'title']
Map
对象保存键值对。任何值(对象或者原始值) 均可以做为一个键或一个值。构造函数Map能够接受一个数组做为参数。Set
对象容许你存储任何类型的值,不管是原始值或者是对象引用。它相似于数组,可是成员的值都是惟一的,没有重复的值。key
的做用主要是为了高效的更新虚拟DOM
,其原理是vue
在patch
过程当中经过key
能够精准判断两个节点是不是同一个,从而避免频繁更新不一样元素,使得整个patch
过程更加高效,减小DOM
操做量,提升性能。 2. 另外,若不设置key
还可能在列表更新时引起一些隐蔽的bug 3. vue
中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue能够区分它们, 不然vue
只会替换其内部属性而不会触发过渡效果。
arguments
,取而代之用rest
参数...解决this
,会捕获其所在的上下文的this值,做为本身的this值call() 或 apply()
方法调用一个函数时,只传入了一个参数,对 this 并无影响。Generator
函数,不能使用yield
关键字总结:
this
永远指向其上下文的 this
,任何方法都改变不了其指向,如call() , bind() , apply()
// 普通的add函数
function add(x, y) {
return x + y
}
// Currying后
function curryingAdd(x) {
return function (y) {
return x + y
}
}
add(1, 2) // 3
curryingAdd(1)(2) // 3
复制代码
原型链继承 写个父类、子类 子类的原型为父类的实例 子类.prootype = new 父类 修正子类原型为子类自己 子类.prototype.constructor=子类 new 子类便可调用父类方法 构造函数继承 写个父类、子类 在子类中父类.call(this) 便可实现
当一个组件须要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,咱们可使用 mapState 辅助函数帮助咱们生成计算属性 mapMutations 其实跟mapState 的做用是相似的,将组件中的 methods 映射为 store.commit 调用
如上图能够粗略的分为两类,多项式量级和非多项式量级。其中,非多项式量级只有两个:O(2n) 和 O(n!) 对应的增加率以下图所示
xxxxx...
osi7层模型:物理层-数据链路层-传输层-网络层-应用层-会话层-表示层
tcp5层模型:物理层-数据链路层-传输层-网络层-应用层
我是伊人a,与你相逢,我很开心。
文中若有错误,欢迎在评论区指正,若是这篇文章帮到了你,欢迎点赞👍和关注😊
本文首发于掘金,未经许可禁止转载💌