# 失败重试
Promise.retry = function (promiseFn, times = 3) {
return new Promise(async (resolve, reject) => {
while (times--) {
try {
var ret = await promiseFn();
resolve(ret);
break;
} catch (error) {
if (!times) reject(error);
}
}
});
};
function getProm() {
const n = Math.random();
return new Promise((resolve, reject) => {
setTimeout(() => n > 0.9 ? resolve(n) : reject(n), 1000);
});
}
Promise.retry(getProm);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 取消Promise
// axios 版本---cancelToken 参数
// 构造函数 axios.CancelToken(执行器函数)
// 工厂方法 cancelToken.source().token
// isCancel
// 拦截器 + source.cancel()
// config.cancelToken.promise.then 里面进行取消执行
// cancelToken(executor)---定义 this.promise,将 resolvePromise 暴露出来,executor里执行并执行Cancel
// 在 xhr 中发现
// token, message
if (config.cancelToken) {
//这里当promise变成成功后,调用了then执行request.abort()这样就取消了这个请求;
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
//取消请求
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
// 定义一个promise属性,把resolve拿出来备用
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
// 把控制状态的方法cancel传给回调函数
// 这样外部就可以控制改变CancelToken的状态了
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
// axios:request + Promise 链式调用
// 常用的功能,拦截器,数据修改器,http请求,就是在这个Promise链式调用中逐步被执行。request方法返回Promise链。我们用的就是这个返回的Promise,执行结果就在这个Promise中的状态值中。
// 连接器需要注册 axios.interceptors.request.use(fulfilled, rejected)
// 终止请求:config.cancelToken.throwIfRequested
// axios.spread?
// 未验证
async function updateUser(token) {
let cancelled = false;
// 我们不调用 reject,因为我们无法访问
// 返回的 Promise
// 我们不调用其它函数
// 在结束时调用 reject
token.cancel = () => {
cancelled = true;
};
const data = await wrapWithCancel(fetchData)();
const userData = await wrapWithCancel(updateUserData)(data);
const userAddress = await wrapWithCancel(updateUserAddress)(userData);
const marketingData = await wrapWithCancel(updateMarketingData)(userAddress);
// 因为我们已经包装了所有的函数,以防取消
// 不需要调用任何实际函数来达到这一点
// 我们也不能调用 reject 方法
// 因为我们无法控制返回的 Promise
if (cancelled) {
throw { reason: 'cancelled' };
}
return marketingData;
function wrapWithCancel(fn) {
return data => {
if (!cancelled) {
return fn(data);
}
}
}
}
const token = {};
const promise = updateUser(token);
// 等一会...
token.cancel(); // 用户还是会被更新
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
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