-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.ts
222 lines (195 loc) · 6.76 KB
/
main.ts
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import axios, {
AxiosInstance,
AxiosPromise,
AxiosRequestConfig,
Method,
Canceler,
AxiosError,
AxiosResponse
} from "axios";
const cancelToken = axios.CancelToken
export interface Protocol {
getRequestConfig(config: AxiosRequestConfig): RequestConfig // 通过axios请求参数来获取原请求接口所有信息
reconnect<R = any>(r: RequestConfig): Promise<R | AxiosResponse<R>> // 重新请求
dispatch<R = any>(r: RequestConfig): Promise<R | AxiosResponse<R>> // 请求方法
getHashCode(r: AxiosRequestConfig): number // 获取请求唯一标识
checkRequestExists(hashCode: number): Boolean // 检测是否有存在相同请求
}
export type MethodType = "default" | "delay" | "block" | "kill"
export interface RequestConfig extends AxiosRequestConfig {
type?: MethodType // 接口类型
reconnect?: Boolean // 是否需要重连
hashCode?: number // 当前请求hashCode
delayTime?: number // 私有化延迟请求时间
cancelHandle?: Canceler // 取消请求回调方法
reconnectTimes?: number // 当前重连次数
}
export interface Config extends AxiosRequestConfig {
maxReconnectTimes?: number // 最大重连次数,默认为5次
delayTime?: number // 延迟毫秒数,默认为300毫秒
reconnectTime?: number // 重连时间间隔
}
interface RequestUniqueObject {
url: string,
method: Method,
}
export class SuperAxios implements Protocol {
public axiosInstance: AxiosInstance // axios单例对象
private queue: Map<number, RequestConfig> = new Map() // 请求队列
private readonly maxReconnectTimes: number = 5 // 最大重连次数,默认为5次
private readonly delayTime: number = 300 // 延迟毫秒数,默认为300毫秒
private Timer?: any // 延时器对象
private readonly reconnectTime: number // 重连时间间隔
constructor(config: Config) {
this.axiosInstance = axios.create(config)
const {
maxReconnectTimes = 5,
delayTime = 300,
reconnectTime = 1500
} = config
this.maxReconnectTimes = maxReconnectTimes
this.delayTime = delayTime
this.reconnectTime = reconnectTime
}
/***
* 重连请求
* @param r
*/
public reconnect<R = any>(r: RequestConfig): Promise<R | AxiosResponse<R>> {
if (r.reconnectTimes! < this.maxReconnectTimes) {
this.queue.delete(this.getHashCode(r))
r.reconnectTimes!++
const Reconnection = new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, this.reconnectTime)
})
return Reconnection.then(() => {
return this.dispatch(r)
});
}
return Promise.reject("已经尽力了,但是网络还是不给力")
}
/***
* http请求最终执行方法
* @param r:RequestConfig
* @return AxiosPromise<R>
* @private
*/
dispatch<R = any>(r: RequestConfig): Promise<R | AxiosResponse<R>> {
if (!r.reconnectTimes) {
r.reconnectTimes = 0
}
switch (r.type) {
case "block":
return this.block(r)
case "delay":
return this.delay(r)
case "kill":
return this.cancel(r)
default:
if (r.reconnect) {
this.queue.set(this.getHashCode(r), r)
}
return this.axiosInstance(r)
}
}
/***
* 堵塞当前请求
* @param r
* @private
*/
private block<R = any>(r: RequestConfig): AxiosPromise<R> {
const hashcode = this.getHashCode(r)
if (this.checkRequestExists(hashcode)) {
return Promise.reject(`在第一次未响应返回前不可重复请求该接口${r.url}`)
}
this.queue.set(hashcode, r)
return this.resolve(r)
}
/***
* 续接promise动作
* @param r
* @private
*/
private resolve<R = any>(r: RequestConfig): AxiosPromise<R> {
const self = this
return new Promise(((resolve, reject) => {
this.axiosInstance(r).finally(() => {
const hashcode = self.getHashCode(r)
self.queue.delete(hashcode)
}).then((res) => {
resolve(res)
}).catch((err: AxiosError) => {
reject(err)
})
}))
}
/***
* 检测是否有存在相同请求
* @param hashCode
* @private
*/
public checkRequestExists(hashCode: number): Boolean {
return this.queue.has(hashCode)
}
/***
* 处理可取消请求
* @param r
* @return RequestConfig
*/
private cancel<R = any>(r: RequestConfig): AxiosPromise<R> {
const hashcode = this.getHashCode(r);
if (this.checkRequestExists(hashcode)) {
this.queue.get(hashcode)?.cancelHandle?.("取消上一次相同请求")
this.queue.delete(hashcode)
}
this.queue.set(hashcode, r)
r.cancelToken = new cancelToken(function (c: Canceler) {
r.cancelHandle = c
})
return this.resolve(r)
}
/***
* 节流请求
* @param r
*/
private delay<R = any>(r: RequestConfig): AxiosPromise<R> {
this.Timer && clearTimeout(this.Timer)
const Reconnection = new Promise<void>((resolve) => {
this.Timer = setTimeout(() => {
resolve();
}, r.delayTime || this.delayTime)
})
return Reconnection.then(() => {
return this.axiosInstance(r)
})
}
/***
* 通过请求参数及请求方法生成唯一标识
* @param r
*/
public getHashCode(r: AxiosRequestConfig): number {
const {url, method} = r
const obj: RequestUniqueObject = {
url: <string>url,
method: <Method>method,
}
var str = JSON.stringify(obj);
var hash = 0, i, chr, len;
if (str.length === 0) return hash;
for (i = 0, len = str.length; i < len; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
}
/***
* 通过AxiosRequestConfig获取RequestConfig
* @param config
*/
public getRequestConfig(config: AxiosRequestConfig): RequestConfig {
return this.queue.get(this.getHashCode(config))!;
}
}