0%

vue分析

源码思维

健壮性

代码在发生预期之外的错误时,其应对错误的能力:即就算出错也能够轻松定位到错误,且减少错误的影响范围。

1
2
3
4
5
6
7
8
9
10
11
//1、不要轻易去相信传入参数,需要判断参数类型
function add(a, b) {
if (typeof a == 'number' && typeof b == 'number') {
return a + b;
} else {
throw new Error('a');
}
}

//2、易错代码用try catch包裹起来
a[0] && a[0].data[0];//取属性之前,先判断其是否存在

defineProperty

主要用于vue的数据绑定,

使用defineProperty中的get来进行设置属性时,这个属性不能被改值,因为只写了get,只能够取到值而不能改值;要能够改值则需要写上set。其实这是一种变量权限的问题,如果该变量是某个属性的话,则可以使用defineProperty来控制其各类权限。

1
2
3
4
5
6
this.$router = this._root._router;
Object.defineProperty(this, '$router', {
get() {
return this._root._router;
}
});

模块支持检测:先判断当前的环境符合的哪种模块规范;cmd、amd、umd,或者CommonJS规范、import规范。

架构模式

工厂模式

通俗而讲:我去构建一个工厂方法,让使用者调用这个工厂方法去拿到他要的对象,而不是自己去构建,即不需要去new。

典型例子:jquery。使用jquery时是DOM时代,频繁获取并操作DOM。工厂模式直接用$()就可以拿到对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//jQuery
(function(window) {
function jquery() {
return new jquery.fn.init();
}
jquery.fn.init.prototype = jquery.fn;
jquery.fn = jquery.prototype = {
init:function() {

}
}
jquery.extend({
//回调。给一个对象,将其添加到jquery上
})
//这样去包装是为了jquery中的方法可以有多种调用方式,
//但对象为引用类型,var b = {}, a = b, c = b,修改b时a、c均会修改,实现改一个均影响到。
window.$ = window.jquery = jquery;
})(window);//定义一个匿名自执行函数,不污染外部全局变量,
//同时后面直接传参(window),减少作用链长度

//vue
(function (global, factory) {

}(this, function () {

}));//this在浏览器环境为window,在node环境为global,不会去写死

建造者模式

在构建一个庞大的框架时,先把整个框架分开成几个模块,=》预制=》然后将各个模块融合在一起。

典型例子:vue-2,构建一个庞大的框架。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Vue(options) {
if (!(this instanceof Vue)) {
warn('Vue is a constructor');
}
this._init(options);
}

initMixin(Vue);
stateMixin(Vue);
eventsMixin(Vue);
lifecycleMixin(Vue);
renderMixin(Vue);
/*为什么非要分开开发,而不是全部放到原型链上即可。
1、由于是团队开发,全放在prototype,可能会收到相互之间的影响

*/

函数式

整体的功能就是一大堆的函数,通过函数之间的相互调用来实现整体的功能。对于javaScript,函数才是一等公民:1、tree-shaking:基于文档流的原理,判断某个函数是否被调用,因此能够webpack时自动删除未被调用的函数。2、组合大于继承。因此函数式编程适用于工具库。

典型例子:Vue3,

设计模式

vue-router、vuex这样的只能有一个,即典型的一个类只有一个实例化对象,即单例模式。实现很容易,就是先判断是否已经被实例化过,如果已经实例化过,就不再实例化;需要通过一个变量判断是否已经实例化过。

1
2
3
4
5
6
7
var _vue;
function install(vue) {
if (install.installed && _vue == vue) return;
//执行安装
install.installed = true;
_vue = vue;
}

代码简洁技巧:jquery中的extend({})方法,传入两个对象时,会将两个对象合并再传入。享元模式:减少重复的代码块的数量,将不同点提取出来作为参数。

1
2
3
4
5
6
7
8
9
10
11
function () {
let target = this;
let source = arguments[0];
if (arguments.length == 2) {
target = this;
source = arguments[1];
}
for (let item in source) {
target[item] = source[item];
}
}

优雅利用原生方法:vue使用defineProperty来实现双向绑定,但只能应用于对象的属性;那么数组怎么来触发更新?将数组原生的push、pop、shift方法加上了能够触发双向绑定的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let arr = ["push", "pop"];
var arrayProto = Array.prototype;
let arrayMethods = Object.create(arraryProto);
//执行以下拷贝,来避免污染原生的原型链
arr.forEach((methos) => {
arrMethods[method] = function() {
let original = arrayProto[method];
let result = original.apply(this, args);
//先找到需要修改的方法,并先将原生方法的功能附加上去;
dep.noyify();//触发数组更新
return result;//保持返回值与原方法一致
//最后只替换数组中的原型链即可
}
})

应用进阶

缓存架构-API

优化方案:快、小、省。

缓存:是所有优化方案里最常用、最有效、可以节省http请求,可以从内存中最快读取数据。

1、选择更快的API、算法,减少时间复杂度;

2、看到网站主要消耗的时间,更多地并不在于代码的执行速度,而在于资源加载的速度,因此文件体积小更重要。一、用webpack压缩treeshaking;二、减少代码重复;

vue3方面的改进:1、快:更快的API,用proxy来代替defineProperty;代理proxy不会去改变原对象;diff算法方面改进:对比新老的DOM,先分析动态DOM,只比对动态的DOM;2、小:函数式API:拥抱tree-shaking,可以很方便地将没有用到的方法取出来,并不附加在工程文件中。

3、省:节省http请求

读取数据的快慢:最慢:网络请求;其次:从硬盘中拿数据;最快:从内存中拿数据。因此请求缓存思路就是:有缓存的话,不去发送请求而是直接从缓存中拿去数据。

缓存架构的技巧:

1、缓存架构需要使用单例模式,即所有的缓存都放在一个里面。

2、权限问题,存缓的区域不能直接拿出去给别人操作。因此,需要隐藏起来,使用匿名自执行函数来进行;但同样,需要外界能够进行读取缓存操作,因此需要返回一个对象,在该对象内有一系列操作缓存的方法。这其实是函数闭包的应用。

3、缓存都会存在副作用:

一、更新问题:使用localstorage、session、cookies缓存时,缓存至本地,需要考虑更新问题。(1)、与后端进行websocket连接,但过于麻烦,没必要;(2)、通过定期轮询,定时器,每隔一段时间向后端发起ajax请求;经常变动的API不要用这种缓存;

使用内存缓存时,是不用考虑更新问题;但内存缓存同样有自己的问题,需要考虑占用内存问题,每往里面加东西,都会占用内存。javascript的内存限制较严重,因此需要做一个限制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
if (!window.mycache) {
window.mycache = (function() {
var cache = {};
var cacheArr = [];
return {
get: function (api) {
return new Promise(() => {
//promise实现异步以及链式调用
if (cache[api]){
resolve(cache[api])
} else {
this.set(api).then(()=> {
if (cacheArr.length > 10) {
let _api = cacheArr.shift();
this.remove(_api);
}
cache[api] = res;
cacheArr.push(api);
//需要确保内存限制,不要占用太多内存
resolve(res);
})
}
})
},
set: function () {
return axios.get(api);
},
remove: function () {

}
}
})();
//放在匿名自执行函数里面
}

vue插件

关键的两个API:Vue.use;Vue.mixin。

Vue.use();原理:将一个方法执行一次,如果该方法中有install属性,就执行其install属性,来代替执行该方法;

Vue.mixin();原理:相当于一个全局混合;(局部混合相当于在组件的export后写mixin),可以混合方法methods、数据data、混合生命周期(生命周期的混入才是核心功能)。即,混入的生命周期操作,所有的组件在对应的生命周期均执行该操作函数。

打包项目=》打包体积过大,可以使用异步加载来减少体积 =》 vuex内容太大;=》vuex异步加载,根据组件来异步加载vuex,放在beforeCreated阶段,在DOM还没有加载好之前,将其之间的依赖关系读取好。

插件的用途:1、提供逻辑复用;2、注入自定义操作;

常用API

Vue.util.defineReative:其实就是Vue自身去做响应式的方法,;一般来说只有data的数据能触发响应。这里,我们可以调用这个API,使外部数据也能触发响应。

用法:1、将localstorage中的数据触发响应,不需要将其取出来;2、监听window的事件,常用的是resize,实现尺寸的自适应;3、监听浏览器版本、内存;

本质是让外部数据也能触发响应。

Vue.extend:传入一个对象时,其会返回一个构造函数,直接new便可以创建实例。用于import,在使用import时,导入的是vue的选项。

vue单元测试=》测某个组件的方法和节点渲染结果

render渲染:提供函数,用JS来表达你的整个template,当页面的逻辑较为复杂时。

API层

Axios源码分析

Axios如何实现请求拦截、响应拦截

1、初始化Axios,其实是调用request方法;

请求拦截器设置的处理——发送请求——响应拦截器设置的处理:这些一大堆方法由数组来存储;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
axios.interceptors.request.use(()=> {

})
axios.interceptors.response.use(()=> {

})
function axios() {
this.interceptors = {
request: new interceptorsManner(),
response: new interceptorsManner()
}
}
function interceptorsManner(){
this.handlers = [];
}
interceptorsManner.prototype.use((fullfilled, rejected) => {
this.handler.push({
fullfilled: fullfilled;
rejected: rejectes;
})
})
-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!