js基础
基本数据类型:
string
,boolean
,number
,undefined
,symbol
,null
引用数据类型:
array
,function
,Date
,RegExp
,object
首页白屏的原因及优化方案
- 当前很多无线页面都使用前端模板进行数据渲染,那么在糟糕的网速情况下,一进去页面,看到的不是白屏就是 loading,这成为白屏问题。
此问题发生的原因基本可以归结为网速跟静态资源
- 1、css文件加载需要一些时间,在加载的过程中页面是空白的。 解决:可以考虑将css代码前置和内联。
- 2、首屏无实际的数据内容,等待异步加载数据再渲染页面导致白屏。 解决:在首屏直接同步渲染html,后续的滚屏等再采用异步请求数据和渲染html。
- 3、首屏内联js的执行会阻塞页面的渲染。 解决:尽量不在首屏html代码中放置内联脚本。(来自翔歌)
- 解决方案 - 根本原因是客户端渲染的无力,因此最简单的方法是在服务器端,使用模板引擎渲染所有页面。同时
- 减少文件加载体积,如html压缩,js压缩
- 加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西
- 使用本地存储处理静态文件。
webpack压缩css/js文件
- compression-webpack-plugin
// gzip压缩*
const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' + productionGzipExtensions.join('|') + ')$'
),
threshold: 10240, *// 只有大小大于该值的资源会被处理 10240*
minRatio: 0.8, *// 只有压缩率小于这个值的资源才会被处理*
deleteOriginalAssets: false *// 删除原文件*
})
)
异步加载js
- 动态创建script标签(jsonp原理一样)
- 伪异步, 将script标签放在body标签的后面
-
window.DOMContentLoaded
和window.onload
这两个事件的区别,前者是在DOM解析完毕之后触发,这时候DOM解析完毕,JavaScript可以获取到DOM引用,但是页面中的一些资源比如图片、视频等还没有加载完,作用同jQuery中的ready事件。后者则是页面完全加载完毕,包括各种资源。
内存泄漏
内存泄漏可以定义为程序不再使用或不需要的一块内存,但是由于某种原因没有被释放仍然被不必要的占有
代码存在逻辑缺陷的时候,你以为你已经不需要,但是程序中还存在着引用,导致程序运行完后并没有合适的回收所占用的空间,导致内存不断的占用,运行的时间越长占用的就越多,随之出现的是,性能不佳,高延迟,频繁崩溃
常见的四种内存泄漏
- 全局变量
- 定时器及回调函数
- dom引用
- 闭包的错误使用
内存的基础理解
- 内存生命周期
- 内存管理系统
- 垃圾回收算法
生命周期
- 分配所需内存
- 读写,使用分配到的内存
- 不需要时释放内存
管理系统
- 手动 和 自动
- 低级语言:像C语言这样的低级语言一般都有底层的内存管理接口,比如 malloc()和free()。
高级语言:JavaScript是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。 释放的过程称为垃圾回收。这个“自动”是混乱的根源,并让JavaScript(和其他高级语言)开发者错误的感觉他们可以不关心内存管理。垃圾回收算法
- 引用计数
这是最初级的垃圾收集算法,如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。(MDN上面的例子)- 标记清除
算法由以下几步组成:
- 垃圾回收器创建了一个“roots”列表。Roots通常是代码中全局变量的引用。JavaScript中,“window”对象是一个全局变量,被当作root。window对象总是存在,因此垃圾回收器可以检查它和它的所有子对象是否存在(即不是垃圾);
- 所有的 roots被检查和标记为激活(即不是垃圾)。所有的子对象也被递归地检查。从root开始的所有对象如果是可达的,它就不被当作垃圾。
- 所有未被标记的内存会被当做垃圾,收集器现在可以释放内存,归还给操作系统了。
闭包
- 闭包就是能够读取其他函数内部变量的函数
- 另一个就是让这些变量的值始终保持在内存中。
String常用方法
String方法 | 作用 |
indexOf() | 返回某个字符在string中第一次出现的位置, 如果没有返回 -1 |
lastIndexOf() | 返回某个字符在string中最后一次出现的位置,如果没有返回 -1 |
includes(‘str’) | 是否包含某个字符, 返回布尔值. |
split(’’) | 切割字符串为数组. |
replace(规则, str) | 替换字符中的某些字符. |
slice(1, 3) | 截取字符串 ; 1 , 3 为提取的起始点和结束点 |
charAt() | 返回指定索引位置处的字符 |
concat() | 拼接字符串 |
substr(), substring() | 截取一个字符串的片段,并返回截取的字符串, substring的参数二是截取返回这个字符串的结束点,并且不包含这个结束点 |
Array常用方法
Array方法 | 作用 |
push()/unshift() | 往数组最后面/最前面添加元素 |
pop()/shift() | 删除数组中最后面/最前面的元素 |
indexOf(’’) | 包含某个元素,返回其索引; |
splice() | 切割数组/替换数组元素. |
slice() | 替换字符中的某些字符. |
Array.from() | |
Array.isArray() | |
HTML5
重绘与重排
重绘不一定需要重排(比如颜色的改变),重排必然导致重绘(比如改变网页位置)
- DOM的变化影响了元素的几何属性,浏览器需要重新计算元素的几何属性,同时其他元素的几何属性和位置也会受到影响,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树,这个过程是重排,浏览器会重新绘制受到影响的部分到屏幕,这个过程叫重绘。
- 重绘重排,优化
1.DOM的增删行为
比如你要删除某个节点,给某个父元素增加子元素,这类操作都会引起回流。如果要加多个子元素,最好使用documentfragment。
2.几何属性的变化
比如元素宽高变了,border变了,字体大小变了,这种直接会引起页面布局变化的操作也会引起回流。如果你要改变多个属性,最好将这些属性定义在一个class中,直接修改class名,这样只用引起一次回流。
3.元素位置的变化
修改一个元素的左右margin,padding之类的操作,所以在做元素位移的动画,不要更改margin之类的属性,使用定位脱离文档流后改变位置会更好。
4.获取元素的偏移量属性
例如获取一个元素的scrollTop、scrollLeft、scrollWidth、offsetTop、offsetLeft、offsetWidth、offsetHeight之类的属性,浏览器为了保证值的正确也会回流取得最新的值,所以如果你要多次操作,最取完做个缓存。
5.页面初次渲染
这样的回流无法避免
6.浏览器窗口尺寸改变
resize事件发生也会引起回流。
这里就不列举引起重绘的行为了,记住,回流一定伴随着重绘,所以上面的行为都会重绘,除此 之外,例如修改背景颜色,字体颜色之类不影响布局的行为都只引发重绘。
HTTP协议
TCP/IP
TCP/IP协议栈主要分为四层:应用层、传输层、网络层、数据链路层,
什么是http协议
- 通过浏览器和服务器进行数据交互,进行超文本(文字,图片,视频等)传输的规定,它规定了超文本传输要遵守的规则
HTTP协议的特点
- HTTP协议是无状态的: 每次HTTP请求都是独立的,任何两个请求之间没有必然的联系,实际应用中并不完全如此,引用了Cookie和Session机制来关联请求
- 多次HTTP请求: 在客户端请求网页时多数情况下并不是一次请求就能成功,服务端首先是响应HTML页面,然后浏览器收到响应后发现HTML页面还引用其他的资源,例如(CSS,JS文件),图片等等,还会自动发送HTTP请求这些需要的资源。现在的HTTP版本支持管道机制,可以同时请求和响应多个请求,大大提高效率
- 基于TCP协议: HTTP协议目的是规定客户端和服务端数据传输的格式和数据交互行为,并不负责数据传输的细节。底层是基于TCP实现的,现在使用的版本当中是默认持久连接的,也就是多次HTTP请求使用一个TCP连接
VUE
Vue 优点
轻量级框架
- 值关注视图层,是一个构建数据的视图集合,大小只有几十kb;
- Vue.js 通过简介的API 提供高效的数据绑定和灵活的组件系统;
双向数据绑定
- 通过MVVM 思想实现数据的双向绑定,让开发者不用再操作DOM 对象,有更多的时间去思考业务逻辑;
组件化
- Vue.js 通过组件,把一个单页面应用中的各种模块拆分到一个一个单独的组件(component)中我们只要现在父级应用中写好各种组件标签(占坑),并且在组件标签中写好要传入组件的参数,然后再分别写好各种组件的实现(填坑),然后整个应用就算完成了;
虚拟DOM
- 把最终的DOM 操作计算出来并优化,由于这个DOM 操作属于预处理操作,并没有真实的操作DOM, 所以叫做虚拟DOM ,最后在计算完毕才真正将DOM 操作提交,将DOM 操作变化反映到DOM 树上;
视图,数据,结构分离
- 使数据的更改更为简单,不需要进行逻辑代码的修改,只需操作数据就能完成相关操作;
Proxy 与 Object.defineProperty() 对比
Proxy 的优点:
- 可以直接监听对象而非属性,并返回一个新对象;
- 可以直接监听数值的变化;
- 可以劫持整个对象,并返回一个新对象;
Proxy 的缺点:
- Proxy 是es6 提供的新特性,兼容性不好,所以导致Vue3.0 一直没有正式发布让开发者使用
Object.defineProperty() 的优点:
- 兼容性好,支持IE9
- IE9 以下的版本不兼容
Object.defineProperty() 的缺点:
- 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应;
- 只能劫持对象的属性,我们需要对每个对象的每个属性进行遍历;
provide和inject
- 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。简单来说就是子孙组件可以访问到祖先的对象方法。
- 在 App.vue 文件里写入provide的方法,
- 然后在需要刷新的子孙组件中用inject注入 App.vue 中provide声明的变量
对MVVM的理解
- M - Model, Model 代表数据模型,也可以在Model 中定义数据修改和操作的业务逻辑;
- V - View, View 代表UI 组件,她负责将数据模型转化为UI 展现出来;
- VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为,处理用户交互;
响应式原理
- 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter, getter
- 默认Vue 在初始化数据时,会给data 中的属性使用Object.defineProperty 重新定义所有属性
- 当页面到对应属性时,会进行依赖收集( 收集当前组件中的watcher )
- 如果属性发生变化会通知相关依赖进行更新操作;
Vue 采用异步渲染
- 因为如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染,所以为了性能考虑,
Vue 会在本轮数据更新后,再去异步更新数据