一.单线程和异步的关系
- 单线程:同一时间只能做一件事
- 原因:避免DOM渲染的冲突
- 解决方案:异步
- 实现方式--event loop
1.什么是单线程,和异步的关系
单线程:同一时间,只能做一件事,<span style="color:red">正是因为js 是单线程,才出现了异步解决方案</span>,
像定时器,如果没有异步的话,页面就一直卡在那等着,所以说,异步是唯一而高效的解决方案2.js为什么是单线程
<span style="color:red">原因避免DOM渲染冲突</span>:
- 浏览器需要渲染DOM
- JS可以修改DOM结构
- js执行的时候,浏览器DOM渲染会暂停
- 两段js也不能同时执行(都修改DOM就冲突了)
- webworker支持多线程,但是不能访问DOM
3.异步带来了哪些问题
- 问题一:没有按照书写方式执行,可读性差
- 问题二:callback中不容易模块化
4. 实现异步的方式--eventloop
- 事件轮询,js实现异步的具体的解决方案
- 同步代码,直接执行
- 异步函数先放在异步队列中
- 待同步函数执行完毕,轮询执行异步队列的函数
5.Promise的基本使用
- 异常捕获
//规定:then只接受一个参数,最后统一用catch捕获异常 resutl.then(function(img){ console.log(img.width) }).then(function(img){ console.log(img.width) }).catch(function(ex){ //最后统一 catch console.log(ex) })
- Promise.all和Promise.race
- Promise标准
6.async/await
- then只是将callback拆分了
- async/await 是最直接的同步写法
[图片上传失败...(image-86d1c6-1595464164685)]
- 用法
[图片上传失败...(image-138a79-1595464164686)]
二.js垃圾回收机制
1.堆栈溢出
当存储的数据达到某一限制就会造成堆栈溢出
2. 内存泄漏
当不断向堆中存储数据,而不进行清理,这就是内存泄漏
3.垃圾回收
语言一般分为两种,一种自动清理,一种手动清理,js只有自动清理
现在各大浏览器通常用采用的垃圾回收有两种方法:标记清除、引用计数。
标记清除
js中最常用的垃圾回收方式就是标记清楚,当变量进入环境时,就标记这个变量为“进入环境“,当变量离开环境时,就将其标记为”离开环境“。 被标记离开环境的变量在下一次垃圾回收启动的时候会被释放掉占用的内存空间
引用计数
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。
- 垃圾回收机制触发条件
IE6的垃圾回收机制是根据内存分配量允许的,当环境中的256个变量,4096个对象,64k的字符串任意一张情况的时候都会触发垃圾回收器工作,bug!!
IE7中做了调整,触发条件不再是固定的多,而是动态修改的,初始值和IE6相同,如果垃圾回收器回收的内存分配量低于程序占用内存的15%,说明大部分内存不可被回收,设的垃圾回收触发条件过于敏感,这时候把临界条件翻倍,如果回收的内存高于85%,说明大部分内存早就该清理了,这时候就把触发条件置回
三 渲染机制
1.Doctype的作用是什么?
作用是为了告诉浏览器该文件的类型。让浏览器解析器知道应该用哪个规范来解析文档 html5 <!Doctype html> HTML 4.01 Strict <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> HTML 4.01 Transitional <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2.浏览器渲染过程
HTML渲染大致分为如下几步:
HTML被HTML解析器解析成DOM Tree, css则被css解析器解析成CSSOM Tree。
DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染树(Render Tree)。
节点信息计算(重排)也叫回流,这个过程被叫做Layout(Webkit)或者Reflow(Mozilla)。即根据渲染树计算每个节点的几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置
渲染绘制(重绘),这个过程被叫做(Painting 或者 Repaint)。即根据计算好的信息绘制整个页面。
以上4步简述浏览器的一次渲染过程,理论上,每一次的dom更改或者css几何属性更改,都会引起一次浏览器的重排/重绘过程,而如果是css的非几何属性更改,则只会引起重绘过程。所以说重排一定会引起重绘,而重绘不一定会引起重排。
触发重排的操作有:
当你增加/删除/修改DOM节点时,会导致重排/重绘
当你移动DOM的位置
当你resize窗口的时候(移动端没有这个问题)
元素尺寸的改变
当你修改网页默认字体时
触发重绘的操作有:
相比重排,重绘就简单多了,所谓重绘,就是当页面中元素样式的改变并不影响
它在文档流中的位置时,例如更改了字体颜色,浏览器会将新样式赋予给元素并重新绘制的过程称。
color border-style visibility background text-decoration background-image background-position background-repeat outline-color outline outline-style border-radius outline-width box-shadow background-size [图片上传失败...(image-491d9d-1595464164686)]
3.为什么操作 DOM 慢
因为 DOM 是属于渲染引擎中的东西,而 JS 又是 JS 引擎中的东西。当我们通过 JS 操作 DOM 的时候,其 实这个操作涉及到了两个线程之间的通信,那么势必会带来一些性能上的损耗。操作 DOM 次数一多,也 就等同于一直在进行线程之间的通信,并且操作 DOM 可能还会带来重绘回流的情况,所以也就导致了性 能上的问题。
四 页面性能类
题目:提升页面性能的方法有哪些
资源压缩合并,减少HTTP请求
非核心代码异步加载->异步加载的方式->异步加载的区别
1.异步加载的方式 1)动态脚本加载 2)defer 3)async 2.异步加载的区别 1)defer是在html解析完成后才会执行,如果是多个,按照加载的顺序依次执行 2)async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关
- 利用浏览器缓存->缓存的分类->缓存的原理
1.缓存的策略 1)强缓存:就是在缓存有效期内直接使用缓存 Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,即在此发起该请 求 时,如果客户端的时间小于Expires的值时,直接使用缓存结果。 在HTTP/1.1中,使用Cache-Contro cache-control: max-age=600 expires: Mon, 16 Apr 2018 01:41:50 GMT 2)协商缓存: 协商缓存就是强制缓存失效后,浏览器携带缓存标识想服务器发起请求, 由服务器根据缓存标识决定是否使用缓 存的过程,主要有以下两种情况: 协商缓存生效,返回304,即数据未更改可以继续使用。 协商缓存失效,返回200,数据已发生更改,并返回客户端新的数据。 Last-Modified / If-Modified-Since ETag
使用CDN
预解析DNS
<link rel="dns-prefetch" href="//img.alicdn.com"> 当遇到a标签但是为了确保安全性,在HTTPS页面中不会自动解析 希望在HTTPS页面开启自动解析功能时,添加如下标记 <meta http-equiv="x-dns-prefetch-control" content="on">
五. vue和react的区别
相同点
1.都支持服务器端渲染
**2.都有Virtual DOM,组件化开发,通过props参数进行父子组件数据的传递,**
都实现webComponent规范
3.数据驱动视图
4.都有支持native的方案,React的React native,Vue的weex
5.都有管理状态,React有redux,Vue有自己的Vuex(自适应vue,量身定做)
6.只有框架的骨架,其他的功能如路由/状态管理等是与框架分离的
7.都是javascript的UI框架,数据驱动试图
不同点
**1.React严格上只针对MVC的view层,Vue则是MVVM模式**
2.virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.
而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,
所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
**3.组件写法不一样, React推荐的做法是 JSX + inline style, **
也就是把HTML和CSS全都写进JavaScript了,即'all in js';
通过js来生成html,所以设计了jsx,还有通过js来操作css,社区的styled-component、jss等
Vue推荐的做法是
webpack+vue-loader
的单文件组件格式,即html,css,jd写在同一个文件;**4.数据绑定: vue实现了数据的双向绑定,react数据流动是单向的** **5.state对象在react应用中不可变的,需要使用setState方法更新状态;**
在vue中,state对象不是必须的,数据由data属性在vue对象中管理;
**6.多了指令系统,让模版可以实现更丰富的功能,而React只能使用JSX语法;**
7.vue基于数据劫持,拦截到最新的数据,从而渲染视图,
react是提供对应的API,通过我们操作API,让最新数据渲染视图
8.react默认只实现了单向控制(只有数据影响视图),
而vue基于v-model实现了双向控制(即也包含了视图影响数据)
无论vue还是react,在实现视图影响数据的方式上,也都是基于change/input事件,
监听表单元素内容的改变,从而去修改数据,达到数据的更新
vue和react选择
- vue:最新文档和更简单的语法,更小,更快,更灵活。丰富的html模版,易于开发
- react:需要构建移动应用程序,专业和出色的社区支持,以解决任何问题。需要构建大型应用程序,轻量级,易于版本歉意
6.MVC(后端node)与前端MVVM之间的区别
MVC 是后端的分层开发概念
MVVM 是前端视图层的概念,主要关注于视图层分离,也就是说:MVVM把前端的视图层,分为了三部分Model,View,ViewModel(VM),其中VM是MVVM思想的核心:因为VM是M和V之间的调度者
MVVM的思想,主要是为了让我们开发者更加方便,因为MVVM提供了数据的双向绑定;
注意:数据的双向绑定是由VM提供的;
<body> <!-- Vue实例所控制的这个元素区域,就是MVVM中的 V --> <div id="app"> <div >{{message}}</div> </div> <script> // new出来的这个VM对象,就是我们MVVM中的 VM 调度者 var vm = new Vue({ el: "#app", // 这里的data就是MVVM中的 M,专门用来保存每个页面的数据的 data: { message: "hello world", } }) </script> </body>
vue
vdom
- vdom是什么?为何会存在vdom?
虚拟dom,用js模拟DOM结构, DOM操作非常”昂贵“,将DOM对比操作放在js层,提高效率 由于在浏览器中操作DOM是很昂贵的。频繁的操作DOM,会产生一定的性能问题。这就是虚拟Dom的产生原因
- key的作用
key得作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过可以精确判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能
vue 2.0 响应式原理
//Vue 2.0 实现相应式原理 //数据变化了,可以更新视图 let oldArrayPrototype = Array.prototype let proto = Object.create(oldArrayPrototype); ['push','shift','unshift'].forEach(method => { proto[method] = function(){ oldArrayPrototype[method].call(this,...arguments) updateView(); } }); function observer(target){ if(typeof target !== 'object' || target == null){ return target } if(Array.isArray(target)){//拦截数组,给数组的方法进行了重写 target.__proto__ = proto } for(let key in target){ defineReactive(target,key,target[key]) } } function defineReactive(target,key,value){ observer(value) //递归 Object.defineProperty(target,key,{ get(){ return value }, set(newValue){ if(newValue !== value){ observer(newValue) updateView(); value = newValue } } }) } function updateView(){ console.log('更新视图'); } let data = {name:'zf',age:{n:200},arr:[0,1,2]} observer(data) data.arr.push(3)
VUE3.0 响应原理
function trigger() { console.log('触发视图更新'); } function isObject(target) { return typeof target == 'object' && target !== null; } function reactive(target) { if (!isObject(target)) { return target } const handlers = { set(target, key, value) { if (target.hasOwnProperty(key)) { trigger(); } return Reflect.set(target, key, value); }, get(target, key, receiver) { const res = Reflect.get(target, key) if (isObject(target[key])) { return reactive(res) //递归 } return res; }, deleteProperty(target, key) { return Reflect.deleteProperty(target, key) } } let observed = new Proxy(target, handlers) return observed } let obj = { name: 'zf', a: [1, 2, 3] } let p = reactive(obj) p.a.push(4)
react
ref
ajax:
异步组件:按需家长
其他面试题
1.进程和线程
https://www.php.cn/faq/418138.html
2.节流和防抖
https://www.jianshu.com/p/757957750792
3.页面布局的方式
流式布局,也叫百分比布局
流式布局的特征:
宽度自适应,高度写死,并不是百分百还原设计图。
图标都是固定死大小的,包括字体等也是固定死的。并不是所有的东西都是自适应的。
一些大的图片,设置宽度为百分比自适应即可,随着屏幕大小进行变化,对于小图标或者文本等, 一般都是定死宽高大小。
等比缩放 rem
响应式布局
4.instance of 原理
<script type="text/javascript">
//自定义一个构造函数
function Fun(){}
//利用上面的构造函数构造一个实例
var fun1 = new Fun()
console.log(fun1 instanceof Fun) //true
console.log(fun1 instanceof Function) //false
console.log(fun1 instanceof Object) //true
</script>
Instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。
Instanceof的判断规则是:沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条 线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。
5.普通函数中的和箭头函数this
箭头函数和普通函数的区别如下。
普通函数:根据调用我的人(谁调用我,我的this就指向谁)
箭头函数:根据所在的环境(我再哪个环境中,this就指向谁)
一针见血式总结:
普通函数中的this:
1. this总是代表它的直接调用者(js的this是执行上下文), 例如 obj.func ,那么func中的this就是obj
2.在默认情况(非严格模式下,未使用 'use strict'),没找到直接调用者,则this指的是 window (常见的window的属 性和方法有: alert, location,document,parseInt,setTimeout,setInterval等)(约定俗成)
3.在严格模式下,没有直接调用者的函数中的this是 undefined
4.使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象
ES6箭头函数中this
(1)默认指向定义它时,所处上下文的对象的this指向。即ES6箭头函数里this的指向就是上下文里对象this指向,偶尔没有上下文对象,this就指向window
(2)即使是call,apply,bind等方法也不能改变箭头函数this的指向
6.http中服务状态码?303,301,302的区别?
HTTP状态码301与302有什么区别2,515次阅读
301:(永久移动)请求的网页已被永久移动到新位置。服务器返回此响应(作为对GET或HEAD请求的响应)时,会自动将请求者转到新位置。
302:(临时移动)服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。此代码与响应GET和HEAD请求的301代码类似,会自动将请求者转到不同的位置。
HTTP状态码301与302的区别:
1、它们之间关键区别在,资源是否存在有效性;
2、301资源还在只是换了一个位置,返回的是新位置的内容;
3、302资源暂时失效,返回的是一个临时的代替页上。
304(未修改)
注意:如果永久失效建议使用404
7.http的缓存机制
https://www.cnblogs.com/chenqf/p/6386163.html
对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
Expires
Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。
不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。
另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。
所以HTTP 1.1 的版本,使用Cache-Control替代。
Cache-Control:max-age=1000
Cache-Control
Cache-Control 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,
默认为private。
private: 客户端可以缓存
public: 客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的)
max-age=xxx: 缓存的内容将在 xxx 秒后失效
no-cache: 需要使用对比缓存来验证缓存数据(后面介绍)
no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多越好, so...基本上和它说886)
对于协商缓存,将缓存信息中的Etag/If-None-Match和Last-Modified/If-Modified-Since通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。
Cache-Control:no-cache
http缓存控制
1.http缓存能够帮助服务器提高并发性能,很多资源不需要重复请求直接从浏览器中拿缓存
2.http缓存分类:强缓存 协商缓存
3.强缓存通过expires和cache-control控制 ,协商缓存通过last-Modify 和E-tag控制
补充:
1.为什么有expires 还需要cache-control
因为expires有个服务器和浏览器时间不同步的问题
expires是绝对时间 cache-control是相对时间
2.last-modify 和 etag
last-modify 它是有个精度问题到秒
e-tag没有精度问题, 只要文件改变 e-tag值就改变
8.对原型和作用域链的理解
原型:
所有的函数都天生自带一个属性:prototype(原型),它是一个对象数据类型的值,在当前prototype对象中,存储了类需要给其实例使用的公有的属性和方法
prototype这个对象,浏览器会默认为其开一个堆内存,这个堆内存中天生自带一个属性:constructor(构造函数),这个属性存储的的值就是当前函数本身
每一个类的实例(每一个对象)都天生自带一个属性:proto,属性值是当前对象所属类的原型(prototype)
原型链:
当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的proto(即它的构造函数的prototype)中寻找,即
console.log(obj.__proto__ === Object.prototype);
作用域链:(当前作用域没有定义某个变量,所以要去它的父级作用域找,这样的就是作用域链)
当前作用域代码执行的时候遇到一个变量,首先看一下它是否属于私有变量,
如果不是私有变量,向其上级作用域查找,也不是上级作用域私有变量,继续向上查找,
一直到window全局作用域为止,
我们把这种向上一级级查找机制叫做作用域链
9.redux
1.store通过reducer创建了初始状态,因为创建容器的时候执行一次DISPATCH
3.用户产生了操作,发送一个action对象到store的dispatch函数里面
4.然后会调用reducer,reducer接收到action并根据action.type去匹配,执行相应的逻辑,返回新的state
5.store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state
(通知事件池中的方法依次执行)
2.view通过store.getState()获取到了store中保存的state挂载在了自己的状态上
redux是如何降state注入到react组件上去
1.首先明确与React产生关联的React-redux这个库
2.Redux的原理就是一个发布订阅器,帮我买用一个变量存储所有的state,并且提供了发布功能来修改数据,以及订阅功能 来触发回调
3.而React-Redux的作用就是订阅Store里数据的更新,他包含两个重要元素,Provider和connect方法
4.Provider的作用就是通过Context API把 Store对象注入到React组件上去
5.而Connect方法就是一个高阶组件,在高阶组件里通过订阅Store中数据的更新,从而通过调用 setState方法来触发
组件更新
redux 最大的弊端是样板代码太多,修改数据的链路太长
解决方案:可借助一些工具,帮我吗减少创建代码的过程,Redux-Actions
10.事件订阅
订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某发布者对象。
这个发布者对象在自身状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态。
class Public{
constructor(){
this.handlers = {}
}
on(eventType,handler){
if(!(eventType in this.handlers)){
this.handlers[eventType] = []
}
this.handlers[eventType].push(handler)
}
emit(eventType){
if(!(eventType in this.handlers)){
return
}
let handlers = this.handlers[eventType]
for(let i=0;i<handlers.length;i++){
handlers[i]()
}
}
off(eventType,fn){
if(!(eventType in this.handlers)){
return
}
let currentHandler = this.handlers[eventType]
let length = currentHandler.length
for(let i=length-1;i>=0;i--){
if(fn === currentHandler[i]){
currentHandler.splice(i,1)
}
}
if(currentHandler.length === 0 ){
delete this.handlers[eventType]
}
}
}
let publish = new Public()
let fn = ()=>{
console.log(1);
}
fn1 = ()=>{
console.log(2);
}
fn2 = ()=>{
console.log(3);
}
11.如何检测一个数组
array.isArray判断,返回true,说明是数组
instanceof Array判断,返回true。说明是数组
12 .vue数据响应式原理
vue.js 则是采用数据劫持+发布订阅模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
13.前端路由
什么是路由?
根据不同的url地址展示不同的页面或者数据
路由分为前端路由和后端路由
前端路由:
1.前端路由多用于单页面开发,也就是SPA
2.前端路由不涉及到服务器的,是前端利用hash或者HTML5的historyApi来实现的,一般用于不同的内容展示和切换
后端路由:
通过用户请求的url导航到具体的html页面;每跳转到不同的URL,都是重新访问服务端,然后服务端返回页面,页面也可以是服务端获取数据,然后和模板组合,返回HTML,也可以是直接返回模板HTML,然后由前端js再去请求数据,使用前端模板和数据进行组合,生成想要的HTML
14.用过哪些的loader和plugins
loader:
style-loader、
css-loader、
sass-loader
file-loader 、
url-loader
babel-loader
vue-loader
plugins:
mini-css-extract-plugin //将css文件提取为独立的文件的插件
html-webpack-plugin //将模板文件和js文件整合到一块
clean-webpack-plugin //清理文件
UglifyJSPlugin
DllPlugin
ParallelUglifyPlugin
15.为什么require是在哪引入都可以,而import必须在文件最前面引入?
require是运行时调用,所以require理论上可以运用在代码的任何地方
import是编译时调用,所以必须放在文件开头
16.对babel的了解
Babel是一个JavaScript编译器
Babel是一个工具链,主要用于将ECMAScript 2015+版本的代码转换为向后兼容的JavaScript语法,可以使之运行在当前和旧版本的浏览器或其他环境中。
下面列出的是Babel能为你做的事情:
语法转换
通过Polyfill方式在目标环境中添加缺失的特性(通过@ babel / polyfill模块)
原始码转换(codemods)
17.前端模块化方案
CommonJS 是服务器模块的规范,Node.js采用了这个规范 同步加载
AMD(require.js) 专门用于浏览器端,模块的加载是异步
CMD(sea.js) 按需加载
ES6 浏览器端,js语言本身的
18.node的核心模块
http、https、fs、qs、path url querystring
19.new操作符干了什么
var Func=function(){
this.name='www'
};
var func=new Func ();
new共经过了4几个阶段
1、创建一个空对象
varobj=new Object();
2、设置原型链
obj.__proto__= Func.prototype;
3、让Func中的this指向obj,并执行Func的函数体。
var result =Func.call(obj);
4、判断Func的返回值类型:
如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。
if (typeof(result) == "object"){
func=result;
}
else{
func=obj;;
}
20.内存溢出和内存泄漏
内存溢出:
一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时,就抛出了内存溢出的错误
内存泄漏:
占用的内存没有及时释放
内存泄漏积累多了就容易导致内存溢出
常见的内存泄漏:
意外的全局变量
没有及时清理的定时器
必包
21.http与https的区别
1、https协议需要到CA (Certificate Authority,证书颁发机构)申请证书,
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的端口也不一样,前者是80,后者是443。
22.fetch 和 axios区别
fetch 是一个底层的api,浏览器原生支持的
axios 是一个封装好的框架
axios:axios函数就是把发送ajax 用promise封装了一下
1)支持浏览器和nodejs发请求 前后短发请求
2)支持promise语法
3)支持自动解析json
4)支持请求进度检测
fetch
优点:
1)浏览器级别原生支持的api
2)原生支持的promise api
3)语法简洁
缺点:
1)不支持文件上传进度检测
2)使用不完美,需要封装
3)默认不带cookie
4)需要手动处理返回的数据
23.输入 URL 到页面渲染的整个流程
1.对域名进行解析,得到ip地址
2.根据ip地址,找到服务器,发起TCP的三次握手
3.建立TCP连接后发起http请求
4.服务器响应HTTP请求,浏览器得到html代码
5.浏览器解析html代码,并请求html代码中的资源(如:js/css/图片)
6.浏览器对页面进行渲染呈现给用户
7服务器关闭连接
1)HTML被HTML解析器解析成DOM Tree, css则被css解析器解析成CSSOM Tree。
如果遇到 script 标签的话,会判断是否存在 async 或者 defer ,前者会并行进行下载并执行 JS,后者会先下载文 件,然后等待 HTML 解析完成后顺序执行。
如果以上都没有,就会阻塞住渲染流程直到 JS 执行完毕。遇到文件下载的会去下载文件
2)DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染树(Render Tree)。
3)节点信息计算(重排)也叫回流,这个过程被叫做Layout(Webkit)或者Reflow(Mozilla)。即根据渲染树计算每个节点的 几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置
4)渲染绘制(重绘),这个过程被叫做(Painting 或者 Repaint)。即根据计算好的信息绘制整个页面。
24.xss 和 csrf
1.xss 跨站脚本攻击
2.xss 浏览器向服务器请求的时候被注入脚本攻击
防范手段:
输入过滤
html字符转译
2. csrf 跨站请求伪造
黑客通过网站B,诱使用户去访问已经登录了的网站A,进行一些违背用户意愿的请求,造成用户损失
防范手段:
请求的时候,加token
25.async/await
async/await使得异步代码看起来像同步代码,这正是它的魔力所在
async +await 原理 generate+yield
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细介绍 Generator 函数的语法和 API,它的异步编程应用请看《Generator 函数的异步应用》一章。
26.清除浮动的方法
1.父级div定义伪类:after
.clearfloat:after{display:block;clear:both;content:"";visibility:hidden;height:0}
2.在结尾处添加空div标签clear:both
原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
优点:简单,代码少,浏览器支持好,不容易出现怪问题
缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空div,让人感觉很不爽
3.父级div定义height
原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题
优点:简单,代码少,容易掌握
缺点:只适合高度固定的布局,要给出精确的高度
4.父级div定义overflow:hidden/auto
原理:触发BFC,浮动元素的高度也参与计算
27.BFC
BFC 全称为 块格式化上下文 (Block Formatting Context) 。
触发BFC规范的元素,可以形成一个独立的容器。不收到外界的影响,从而解决一些布局的问题
如何创建BFC
1、float的值不是none。
2、position的值不是static或者relative。
3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
4、overflow的值不是visible
BFC特性及应用
解决margin叠加问题
解决margin传递问题
解决浮动问题
解决覆盖问题
28.元素水平垂直居中
.box{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.box{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.parent{
display: flex;
justify-content: center;
align-items: center;
}
29.ES6 新特性
(1)新增声明命令let和const
(2)模板字符串(Template String)
(3)函数的扩展
函数的默认参数
箭头函数
(4)对象的扩展
属性的简写。ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值
方法的简写。省略冒号与function关键字
(6)import和export ES6标准中,JavaScript原生支持模块(module)了
(7)Promise对象
(8)解构赋值
(10)展开运算符(...)
30 事件冒泡和事件捕获
事件冒泡 事件冒泡:事件会从最内层的元素开始发生,一直向上传播,直到document对象。
事件捕获 事件捕获:与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。 第一个参数是需要绑定的事件,第二个参数是触发事件后要执行的函数。而第三个参数默认值是false,表示在事件冒泡的阶段调用..
31.js如何解决异步的
回调函数
事件触发
发布/订阅者模式
promise
generate
32 promise
class MyPromise{
constructor(exec){
this.status = "pending"
this.value = undefined
this.resolveArr = []
this.rejectArr = []
let change = (status,value)=>{
if(this.status !== "pending") return
this.status = status
this.value = value
let fnArr = this.status === 'resolve' ? this.resolveArr : this.resolveArr
fnArr.forEach((item)=>{
if(typeof item !== 'function'){
return
}
item(this.value)
})
}
let resolve = (value)=>{
if(this.rejectArr.length > 0){
change('resolve',value)
}
let timer = setTimeout(()=>{
change('resolve',value)
clearTimeout(timer)
},0)
}
let reject = (value)=>{
if(this.rejectArr.length > 0){
change('reject',value)
}
let timer = setTimeout(()=>{
change('reject',value)
clearTimeout(timer)
},0)
}
try{
exec(resolve,reject)
}catch(err){
reject(err.message)
}
}
then(resolve,reject){
this.resolveArr.push(resolve)
this.rejectArr.push(reject)
}
}
new MyPromise((resolve, reject) => {
setTimeout(_ => {
resolve(100);
//reject('ERROR');
}, 1000);
}).then(result => {
console.log(result);
})
33.深复制
function cloneObject(target,source){
var names = Object.getOwnPropertyNames(source)
for(let i=0;i<names.length;i++){
var desc = Object.getOwnPropertyDescriptor(source,names[i])
if(typeof desc.value == 'object' && desc.value !==null){
switch(desc.value.constructor){
case RegExp:
obj = new desc.value.constructor(desc.value.source,desc.value.flags)
break;
default:
obj = new desc.value.constructor()
}
cloneObject(obj,desc.value)
Object.defineProperty(target,names[i],{
value:obj,
enumerable:desc.enumerable,
writable:desc.writable,
configurable:desc.configurable
})
}else{
Object.defineProperty(target,names[i],desc)
}
}
return target
}
性能优化
初始阶段->加载优化
- 首页加载慢的优化
问题分析
- 首页加载图片过多
- 首页的请求量过多
- 首页请求的静态资源(html/css/js/图片)过大
结论:所有加载慢的问题最终都可以归纳成两个问题 多和大
Q:首页加载图片过多的问题,可以通过以下几种方法解决:
1)通过懒加载的方式处理非首屏的图片
2)对于小图标可以采用iconfont的方式解决
3)对于小图片可以采用雪碧图的方式解决
Q:首页的请求量过多怎么解决?
如何分析:
1.先通过浏览器的Network可以确定首页加载的资源和请求量
- request:请求数量
- resources:前端资源总大小
- DOMContentLoaded:浏览器已经完全加载了HTML,其他静态资源(js,css,图片等)
- load:浏览器已经加载了所有的静态资源
2.通过converge来查看代码的使用状况
- 只针对js和css
- 可以看出哪些代码虽然加载了但是没有执行
- 没有执行的代码可以考虑一下是否可以懒加载
A:可以通过减少资源的请求量
- 通过nginx服务器来做资源文件合并--将多个js/css文件合并成一个(nginx 添加nginx-http-concat模块)
- 通过打包工具来做资源文件的物理打包
总结
1)通过nginx服务器来做资源文件的合并或者通过webpack等打包工具进行物理打包
2) 在代码层面,对于需要引入一些大型第三方库的时候,可以通过特定的Babel插件来进行按需加载
3)还有可以使用react lazy或其他动态导入方案来进行前端路由层面的动态加载,从而可以减少
首页的js和css的大小
答题思路
对于首页加载慢的问题,一般是由于加载资源过多,并且资源过大导致。 所以应对的策略就减少资源的数量以及减小资源的大小 1)对于图片可以懒加载,减少首屏图片加载量。小图片使用雪碧图来解决,最大程度减少首屏图片数量,从而提升 首页渲染性能 2)对于其他资源可以通过打包(nginx-http-concat或者webpack打包)来合并资源,并可以通过懒加载路由的方 式来减小首页js的加载量 3)减小资源的方式可以通过压缩和混淆加密来减小文件体积,图片可以使用工具来压缩或者使用webp格式 4)同时可在服务器开始gzip压缩来最大化减少所有文件体积
- 优化图片的做法
1)可以通过懒加载减少图片的请求,或者通过雪碧图来合并图片,以及将小图转化成base64的格式,来解决请多的 问题 2)图片大的问题,可以通过自动化压缩工具来压缩图片,或者使用webp格式的图片
实现webpack打包优化
实现CDN加速
CDN 服务器主要是用来放静态资源的服务器,可以用来加速静态资源的下载 CDN 之所以能够加速,是因为会在很多地方都部署 CDN 服务器,如果用户需要下载静态资源,会自动选择最近的节点下载 同时由于 CDN 服务器的地址一般都跟主服务器的地址不同,所以可以破除浏览器对同一个域名发送请求的限制
函数的副作用
结构复制。。。
hooks
dea
set map