单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。有些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的window对象等。
1. 实现单例模式
主要思路:用一个变量来标志当前是否已经为某个类创建过对象,如果是,那么在下次获取该类的实例时,直接返回之前创建的对象。
版本一:使用类的静态属性和静态方法实现单例模式
const Singleton = function (name) {
this.name = name
this.instance = null
}
// 原型链上挂载的方法
Singleton.prototype.getName = function () {
return this.name
}
// 静态方法
Singleton.getInstance = function (name) {
if (!this.instance) {
this.instance = new Singleton(name)
}
return this.instance
}
const a = Singleton.getInstance('sven1')
const b = Singleton.getInstance('sven2')
console.log(a === b)
版本二:使用闭包和静态方法实现单例模式
const Singleton = function (name) {
this.name = name
}
Singleton.prototype.getName = function () {
return this.name
}
Singleton.getInstance = (function () {
let instance = null
return function (name) {
if (!instance) {
instance = new Singleton(name)
}
return instance
}
})()
const a = Singleton.getInstance('aaa')
const b = Singleton.getInstance('bbb')
console.log(a === b)
版本三:惰性单例
惰性单例指的是在需要的时候才创建对象实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="loginBtn">登录</button>
<script>
var getSingle = function (fn) {
var result
return function () {
return result || (result = fn.apply(this, arguments))
}
}
var createLoginLayer = function () {
var div = document.createElement('div')
div.innerHTML = '我是登录浮窗'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
var createSingleLoginLayer = getSingle(createLoginLayer)
document.getElementById('loginBtn').onclick = function () {
var loginLayer = createSingleLoginLayer()
loginLayer.style.display = 'block'
}
</script>
</body>
</html>
2. 实践中的单例模式
2.1 axios取消重复请求
import axios from "axios";
const CancelToken = axios.CancelToken;
let cancelId = 0;
let cancelArray = [];
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在请求时,可以添加自己的特点标识去筛选出需要重复取消的接口
const source = CancelToken.source();
cancelId++;
const id = cancelId;
config.cancelId = id;
config.cancelToken = source.token;
const cancelIndex = cancelArray.findIndex(e => e.url === config.url);
cancelArray.push({
id,
url: config.url,
source
})
if (cancelIndex > -1) {
cancelArray[cancelIndex].source.cancel('取消重复请求');
cancelArray.splice(cancelIndex, 1)
}
return config;
}, function (error) {
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
const cancelIndex = cancelArray.findIndex(e => e.id === response.cancelId);
if (cancelIndex >= -1) {
cancelArray.splice(cancelIndex, 1)
}
// 对响应数据做点什么
return response;
}, function (error) {
if (axios.isCancel(error)) {
// 如果是取消的接口,可以自行返回一个特定标识
console.log('isCancel')
} else {
// 对响应错误做点什么
return Promise.reject(error);
}
});
export default axios