promise
# promise 简介
# promise 基本原理
promise 的核心原理其实就是发布订阅模式,通过两个队列来缓存成功的回调(onResolve)和失败的回调(onReject)
# promise 规范
Promises/A+ (opens new window)
Promise 必须处于以下三种状态之一:待处理、已完成或已拒绝。
Promise 必须提供一个 then 方法来访问当前或最终的值或原因。
Promise 解决程序
# promise 三种状态
pending: 初始状态,既不是成功,也不是失败
fulfilled: 成功
rejected: 失败
# Promise 值穿透
Promise 值穿透:.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。
Promise.resolve("foo")
.then(Promise.resolve("bar"))
.then(function(result) {
console.log(result);
}); // 输出foo
2
3
4
5
Promise.resolve(1)
.then(function() {
return 2;
})
.then(Promise.resolve(3))
.then(console.log); // 输出2
2
3
4
5
6
Promise.resolve(1)
.then(function() {
return 2;
})
.then(function() {
return Promise.resolve(3);
})
.then(console.log); // 输出3
2
3
4
5
6
7
8
Promise.resolve(1)
.then(function() {
return 2;
})
.then(() => {
Promise.resolve(3);
})
.then(console.log); // 输出undefined
2
3
4
5
6
7
8
Promise 方法链通过 return 传值,没有 return 就只是相互独立的任务而已
# Promise 异常穿透
// 实验一
new Promise((resolve, reject) => {
reject(1); //失败状态
})
.then(
(value) => {
console.log("成功", value);
},
(reason) => {
console.log("失败", reason); // 输出:失败 1;无返回值、默认返回成功状态,状态值为undefined
}
)
.then(
(value) => {
console.log("成功", value); // 输出:成功 undefined
},
(reason) => {
console.log("失败", reason);
}
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//实验二(每个then方法中拥有reject回调函数:和实验一中运行结果相同)
new Promise((resolve, reject) => {
reject(1); //失败状态
})
.then(
(value) => {
console.log("成功", value);
},
(reason) => {
console.log("失败", reason); // 输出:失败 1;无返回值、默认返回成功状态,状态值为undefined
}
)
.then(
(value) => {
console.log("成功", value); // 输出:成功 undefined
},
(reason) => {
console.log("失败", reason);
}
)
.catch((reason) => console.log("失败", reason));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 实验三(每个then方法中没有reject回调函数:运行结果与上面两个实验出现偏差)
new Promise((resolve, reject) => {
reject(1); //失败状态
})
.then((value) => {
console.log("成功", value); //没有指定失败的回调函数,不执行代码,去往下一级寻找失败状态回调函数
})
.then((value) => {
console.log("成功", value); //没有指定失败的回调函数,不执行代码,去往下一级寻找失败状态回调函数
})
.catch((reason) => console.log("失败", reason)); // 输出:失败 1;
//当then方法中没有指定失败的回调函数时,
//使用.catch会默认为没有指定失败回调函数的.then指定失败回调函数为:
(reason) => {
throw reason; //注意不是return reason 而是throw reason ;throw保证了返回结果为失败
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//实验四(对比实验三:验证catch的异常穿透是一层层传递下来的并非一次失败状态直接传递到catch)
new Promise((resolve, reject) => {
reject(1); //失败状态
})
.then((value) => {
console.log("成功", value); // 没有指定失败的回调函数,不执行代码,去往下一个.then
})
.then(
(value) => {
console.log("成功", value);
},
(reason) => {
// 指定失败的回调函数,执行失败的回调函数,没有调用catch
console.log("失败hhhhh", reason); // 输出:失败hhhhh 1; 没有调用catch
}
)
.catch((reason) => console.log("失败", reason));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
总结:
异常穿透的前提条件是所有的.then 都没有指定失败状态的回调函数。
如果.catch 前的所有.then 都指定了失败状态的回调函数,.catch 就失去了意义。
.catch 所谓的异常穿透并不是一次失败状态就触发 catch,而是一层一层的传递下来的。
当使用.catch 时,会默认为没有指定失败状态回调函数的.then 添加一个失败回调函数(上文中有具体函数代码)
参考:https://www.cnblogs.com/xjt31/p/14016930.html (opens new window)
# 中断 Promise
- 中断调用链:在 then/catch 的最后一行返回一个永远 pending 的 promise 即可
somePromise
.then(() => {})
.then(() => {
// 终止 Promise 链,让下面的 then、catch 和 finally 都不执行
return new Promise((resolve, reject) => {});
})
.then(() => console.log("then"))
.catch(() => console.log("catch"))
.finally(() => console.log("finally"));
2
3
4
5
6
7
8
9
- 中断 Promise:在合适的时候,把 pending 状态的 promise 给 reject 掉。
注意这里是中断而不是终止,因为 Promise 无法终止
包装一个中断函数,使用 Promise.race 竞速方法:
const request = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("收到服务端数据");
}, Math.random() * 3000);
});
function abortWrapper(p1) {
let abort;
let p2 = new Promise((resolve, reject) => (abort = reject));
let p = Promise.race([p1, p2]);
p.abort = abort;
return p;
}
const req = abortWrapper(request);
req.then((res) => console.log(res)).catch((e) => console.log(e));
setTimeout(() => req.abort("用户手动终止请求"), 2000); // 这里可以是用户主动点击
// 虽然 promise 被中断了,但是 promise 并没有终止,网络请求依然可能返回,只不过那时我们已经不关心请求结果了。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# promise 原型方法
# then()
作用:为 Promise 实例添加状态改变时的回调函数
参数:第一个参数是 resolved 状态的回调函数、第二个参数是 rejected 状态的回调函数,它们都是可选的。
then 方法返回的是一个新的 Promise 实例(注意,不是原来那个 Promise 实例)。因此可以采用链式写法
如果回调函数返回的是普通值,那么将会在下一个 then 中作为回调函数参数被接收
如果回调函数返回的是一个 Promise, 下一个 then 方法将会等待这个 Promise 执行结束,并接收 Promise 的执行结果
# catch()
作用:用于指定发生错误时的回调函数
Promise catch 后面的 then 还是会执行吗?
catch 也会返回一个 promise 所以可以继续 then
# finally()
作用:用于指定不管 Promise 对象最后状态如何,都会执行的操作
# promise 实例方法
# all()
作用:用于将多个 Promise 实例,包装成一个新的 Promise 实例
多个 promise 的返回状态都为 fulfilled,才会变成 fulfilled
多个 promise 的返回状态有一个为 rejected,就会变成 rejected
参数:参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
手写 Promise.all()
function Promiseall(promises) {
const iterator = Symbol.iterator;
if (!promises[iterator]) return;
return new Promise((resolve, reject) => {
const resolvearr = [];
const rejectarr = [];
for (let i of promises) {
if (!(i instanceof Promise)) {
i = Promise.resolve(i);
}
i.then((res) => {
resolvearr.push(res);
}).catch((err) => {
rejectarr.push(err);
});
}
setTimeout(() => {
return rejectarr.length === 0
? resolve(resolvearr)
: reject(rejectarr[0]);
});
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Promise.all 并发控制
- 第三方库实现,比如 async-pool、es6-promise-pool、p-limit
参考:Promise.all 并发限制 (opens new window)
- asyncPool ES6 实现
function asyncPool(poolLimit, array, iteratorFn) {
let i = 0;
const ret = []; // 存储所有的异步任务
const executing = []; // 存储正在执行的异步任务
const enqueue = function() {
if (i === array.length) {
return Promise.resolve();
}
const item = array[i++]; // 获取新的任务项
const p = Promise.resolve().then(() => iteratorFn(item, array));
ret.push(p);
let r = Promise.resolve();
// 当poolLimit值小于或等于总任务个数时,进行并发控制
if (poolLimit <= array.length) {
// 当任务完成后,从正在执行的任务数组中移除已完成的任务
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= poolLimit) {
r = Promise.race(executing);
}
}
// 正在执行任务列表 中较快的任务执行完成之后,才会从array数组中获取新的待办任务
return r.then(() => enqueue());
};
return enqueue().then(() => Promise.all(ret));
}
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
在 ES6 的实现版本中,通过内部封装的 enqueue 函数来实现核心的控制逻辑。当 Promise.race(executing) 返回的 Promise 对象变成已完成状态时,才会调用 enqueue 函数,从 array 数组中获取新的待办任务。
- asyncPool ES7 实现
async function asyncPool(poolLimit, array, iteratorFn) {
const ret = []; // 存储所有的异步任务
const executing = []; // 存储正在执行的异步任务
for (const item of array) {
// 调用iteratorFn函数创建异步任务
const p = Promise.resolve().then(() => iteratorFn(item, array));
ret.push(p); // 保存新的异步任务
// 当poolLimit值小于或等于总任务个数时,进行并发控制
if (poolLimit <= array.length) {
// 当任务完成后,从正在执行的任务数组中移除已完成的任务
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e); // 保存正在执行的异步任务
if (executing.length >= poolLimit) {
await Promise.race(executing); // 等待较快的任务执行完成
}
}
}
return Promise.all(ret);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在以上代码中,充分利用了 Promise.all 和 Promise.race 函数特点,再结合 ES7 中提供的 async await 特性,最终实现了并发控制的功能。利用 await Promise.race(executing); 这行语句,我们会等待 正在执行任务列表 中较快的任务执行完成之后,才会继续执行下一次循环。
# 手写 “符合“ Promises/A+ 规范的 Promise
# ES6 实现
class Promise {
constructor(executor) {
this.state = "pending";
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
let reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
// 解决 onFufilled,onRejected 没有传值的问题
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
// 每次调用 then 都返回一个新的 promise Promise/A+ 2.2.7
let promise2 = new Promise((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
try {
resolvePromise(promise2, onFulfilled(this.value), resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === "rejected") {
setTimeout(() => {
try {
resolvePromise(promise2, onRejected(this.reason), resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === "pending") {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
resolvePromise(
promise2,
onFulfilled(this.value),
resolve,
reject
);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
resolvePromise(
promise2,
onRejected(this.reason),
resolve,
reject
);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
// catch 方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
static resolve(val) {
return new Promise((resolve, reject) => {
resolve(val);
});
}
//添加 reject 方法
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
//添加 all 方法
static all(promises) {
//返回结果为 promise 对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0;
let arr = [];
//遍历
for (let i = 0; i < promises.length; i++) {
//
promises[i].then(
(v) => {
//得知对象的状态是成功
//每个 promise 对象 都成功
count++;
//将当前 promise 对象成功的结果 存入到数组中
arr[i] = v;
//判断
if (count === promises.length) {
//修改状态
resolve(arr);
}
},
(r) => {
reject(r);
}
);
}
});
}
// 添加 race 方法
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(v) => {
//修改返回对象的状态为 『成功』
resolve(v);
},
(r) => {
//修改返回对象的状态为 『失败』
reject(r);
}
);
}
});
}
// 添加 finally 方法
static finally(onFinished) {
return this.then((val) => {
onFinished();
return val;
}).catch((err) => {
onFinished();
return err;
});
}
}
// 解决链式调用和循环引用问题
function resolvePromise(promise2, x, resolve, reject) {
// 循环引用报错 Promise/A+ 2.3.1
if (x === promise2) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
let called;
// x 不是 null 且 x 是对象或者函数
if (x != null && (typeof x === "object" || typeof x === "function")) {
try {
let then = x.then;
// 如果 then 是函数,就默认是 promise 了
if (typeof then === "function") {
// 就让 then 执行 第一个参数是 this 后面是成功的回调 和 失败的回调
then.call(
x,
(y) => {
// 成功和失败只能调用一个
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
(err) => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);
}
);
} else {
resolve(x);
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
module.exports = Promise;
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
参考:https://developer.aliyun.com/article/613412 (opens new window)
# ES5 实现
function Promise(executor) {
this.state = "pending";
this.onFulfilledCallback = [];
this.onRejectedCallback = [];
const self = this;
function resolve(value) {
setTimeout(function() {
if (self.state === "pending") {
self.state = "fulfilled";
self.data = value;
for (let i = 0; i < self.onFulfilledCallback.length; i++) {
self.onFulfilledCallback[i](value);
}
}
});
}
function reject(reason) {
setTimeout(function() {
if (self.state === "pending") {
self.state = "rejected";
self.data = reason;
for (let i = 0; i < self.onRejectedCallback.length; i++) {
self.onRejectedCallback[i](reason);
}
}
});
}
try {
executor(resolve, reject);
} catch (reason) {
reject(reason);
}
}
Promise.prototype.then = function(onFulfilled, onRejected) {
const self = this;
let promise2;
return (promise2 = new Promise(function(resolve, reject) {
if (self.state === "fulfilled") {
setTimeout(function() {
if (typeof onFulfilled === "function") {
try {
const x = onFulfilled(self.data);
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
} else {
resolve(self.data);
}
});
} else if (self.state === "rejected") {
setTimeout(function() {
if (typeof onRejected === "function") {
try {
const x = onRejected(self.data);
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
} else {
reject(self.data);
}
});
} else if (self.state === "pending") {
self.onFulfilledCallback.push(function(promise1Value) {
if (typeof onFulfilled === "function") {
try {
const x = onFulfilled(self.data);
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
} else {
resolve(promise1Value);
}
});
self.onRejectedCallback.push(function(promise1Reason) {
if (typeof onRejected === "function") {
try {
const x = onRejected(self.data);
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
} else {
reject(promise1Reason);
}
});
}
}));
};
function promiseResolutionProcedure(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
if (x instanceof Promise) {
if (x.state === "pending") {
x.then(function(value) {
promiseResolutionProcedure(promise2, value, resolve, reject);
}, reject);
} else if (x.state === "fulfilled") {
resolve(x.data);
} else if (x.state === "rejected") {
reject(x.data);
}
return;
}
if (x && (typeof x === "object" || typeof x === "function")) {
let isCalled = false;
try {
let then = x.then;
if (typeof then === "function") {
then.call(
x,
function resolvePromise(y) {
if (isCalled) return;
isCalled = true;
return promiseResolutionProcedure(promise2, y, resolve, reject);
},
function rejectPromise(r) {
if (isCalled) return;
isCalled = true;
return reject(r);
}
);
} else {
resolve(x);
}
} catch (e) {
if (isCalled) return;
isCalled = true;
reject(e);
}
} else {
resolve(x);
}
}
module.exports = Promise;
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
参考:http://febook.hzfe.org/awesome-interview/book1/coding-promise (opens new window)
# 测试代码
- 暴露一个简单的适配器接口
// test.js
// 导入我们写好的 promise
const Promise = require("./promise.js");
// 根据官方文档暴露一个 deferred 方法,返回一个包含 promise、resolve、reject 的对象
Promise.deferred = function() {
const obj = {};
obj.promise = new Promise(function(resolve, reject) {
obj.resolve = resolve;
obj.reject = reject;
});
return obj;
};
module.exports = Promise;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 运行命令
npx promises-aplus-tests test.js
- 测试结果
872 passing
完美通过!
# 手写 Promise 请求超时功能
思路:声明一个超时 Promise,用 Promise.race 方法让超时 Promsie 和请求 Promise 抢跑
function delayPromise(ms) {
return new Promise(function(resolve) {
setTimeout(resolve, ms);
});
}
function timeoutPromise(promise, ms) {
var timeout = delayPromise(ms).then(function() {
throw new Error("Operation timed out after " + ms + "ms");
});
return Promise.race([promise, timeout]);
}
//运行实例
var taskPromise = new Promise(function(resolve) {
//随便一些什么处理
var delay = Math.random() * 2000;
setTimeout(function() {
resolve(delay + "ms");
}, delay);
});
timeoutPromise(taskPromise, 1000)
.then(function(value) {
console.log("taskPromise在规定时间内结束:" + value);
})
.catch(function(error) {
console.log("发生超时", error);
});
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
参考:https://blog.csdn.net/fangxuan1509/article/details/103729526 (opens new window)
https://www.jianshu.com/p/d66421c826ae (opens new window)
# Promise 实现 js 锁的功能
class Lock {
constructor() {
this.flag = false;
this.data = {}; // 这个data可以根据业务需要保留或移除,是用于传递值的。
}
wait() {
// 等待锁
return new Promise((resolve) => {
if (this.flag) {
resolve(this.data);
} else {
this.resolve = resolve;
}
});
}
notify(data = {}) {
// 通知锁
this.data = data;
this.flag = true;
this.resolve && this.resolve(this.data);
}
}
// 小程序
export default {
data() {
lock: new Lock();
},
onLoad(e) {
// 这里进行参数处理等业务
this.lock.notify(); // 通知对方当前参数已经初始化完成了
},
async onReady() {
// 这里做一些页面元素的一些初始化操作,例如获取canvasContext等等
await this.lock.wait(); // 等待onLoad参数执行完毕
// 这里可以继续往下处理后面的业务了
},
};
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
# Promise 问题
# 1. promise 和 async 和区别
async 简洁,可以让异步代码看起来就像同步代码那样,提高可读性
错误处理 Async/Await 让 try/catch 可以同时处理同步和异步错误,Promise 中。我们需要使用.catch
错误栈,async/await 中的错误栈会指向错误所在的函数,Promise 链中返回的错误栈没有给出错误发生位置的线索
async 调试简单,如果你在.then 代码块中设置断点,使用 Step Over 快捷键,调试器不会跳到下一个.then,因为它只会跳过异步代码。
# js 实现最多发送三个并发请求,后续有多个请求在等待发送
串行:一个异步请求完成了之后再进行下一个请求
并行:多个异步请求同时进行
三个并发需求:搞一个数组 把三个异步请求 push 进去 然后 for 循环遍历 就是 并发了
注意点:
这个数组可能 不止 3 个元素 可能还有 5 6 7 8 个
我可能只推入两个异步请求
怎么知道三个请求什么时间执行完毕:令牌, 可以给个令牌 标识这三个请求 每个请求发一个令牌,请求回来之后 归还令牌 就可以标识
实现步骤:
有个请求的队列 长度最长是三 但并不是由他决定的 而是由令牌数组 长度决定的
有一个等待请求的队列
有一个获取令牌的 方法
有一个归还令牌的方法
代码:
let tokensRequest = {
state: ["token1", "token2", "token3"], // 默认三个令牌 最多可并发发送三次请求
queue: [], // 请求队列
waitqueue: [], // 等待队列
// 获取令牌
getToken: function() {
return this.state.splice(0, 1)[0];
},
// 归还令牌
backToken: function(token) {
this.state.push(token);
},
// 请求队列
pushQueue: function(args, type = "first") {
type == "second" && (this.queue = []); // 每次push新请求的时候 队列清空
for (var i = 0; i < args.length; i++) {
if (this.state.length > 0) {
// 看是否有令牌
var token = this.getToken(); // 取令牌
var obj = {
token,
request: args[i],
};
this.queue.push(obj);
} else {
// 否则推入等待队列
this.waitqueue.push(args[i]);
}
}
},
// 开始执行
start: function() {
for (let item of this.queue) {
item.request().then((res) => {
console.log(res);
this.backToken(item.token); // 令牌归还
if (this.waitqueue.length > 0) {
var wait = this.waitqueue.splice(0, 1);
this.pushQueue(wait, "second"); // 从等待队列进去的话 就是第二中的push情况了
this.start(); // 重新开始执行队列
}
});
}
},
};
// 测试结果
function f1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("11111");
}, 1000);
});
}
function f2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("22222");
}, 2000);
});
}
function f3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("33333");
}, 3000);
});
}
function f4() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("44444");
}, 4000);
});
}
tokensRequest.pushQueue([f1, f2, f3, f4]);
tokensRequest.pushQueue([f2]);
tokensRequest.start();
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
参考:https://blog.csdn.net/yunchong_zhao/article/details/115792198 (opens new window)
# try/catch 无法捕获 promise.reject 原因
1、 try catch 无法捕获异步代码错误
2、 Promise.reject 是一个异步方法
# Promise Catch 后面的 then 还会执行吗?
catch 没有返回 Promise.reject 会执行
// 函数A只返回一个reject异常
function A() {
return Promise.reject(new Error(Math.random()));
}
// 这样会先执行catch,然后执行后面的then
A()
.then(() => console.log("第一个then"))
.catch((e) => console.log(e))
.then(() => console.log("第二个then")); // 会执行
2
3
4
5
6
7
8
9
10
catch 返回 Promise.reject 不会执行
// 函数A只返回一个reject异常
function A() {
return Promise.reject(new Error(Math.random()));
}
// 这样会先执行catch,然后执行后面的then
A()
.then(() => console.log("第一个then"))
.catch((e) => Promise.reject(new Error(Math.random())))
.then(() => console.log("第二个then"));
2
3
4
5
6
7
8
9
10