# 异步编程promise
# 状态
- 状态值
- pending 连接状态
- fulfilled 成功状态
- reject 拒绝状态
- 状态是不可逆的,状态谁先改变则是谁
- 有两个回调函数
resolve
成功reject
失败
# then
- 包含两个回调函数,一个成功回调,一个失败回调
new Promise((resolve, reject) => {
resolve('成功')
}).then(result => {
console.log(result)
})
new Promise((resolve, reject) => {
reject('失败')
}).then(null, reason => {
console.log(reason)
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
链式调用,优先执行先定义的
then
方法new Promise((resolve, reject) => { resolve('成功') }).then(res => { console.log(res) }).then(res => { console.log(res) }) // 成功, undefined
1
2
3
4
5
6
7
8每个
then
方法返回的也是一个promise
let p1 = new Promise((resolve, reject) => { resolve('成功') }) let p2 = p1.then(value => { console.log(value) }, reason => { console.log(reason) }) setTimeout(() => { console.log(p1) console.log(p2) }) // ’成功', p1, p2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16多个
then
方法时,下一个then
方法是对上一个then
返回(return)的值进行处理,且默认状态是resolve
成功new Promise((resolve, reject) => { reject("失败"); }).then( result => console.log(result), reason => console.log(reason) ).then( result => console.log("成功"), reason => console.log("失败") ) // 失败, 成功 new Promise((resolve, reject) => { resolve("成功"); }).then( result => { return new Promise((resolve, reject) => { reject('第二个错误promise') }) }, reason => console.log(reason) ).then( result => console.log("成功"), reason => console.log('error ' + reason) ) // error 第二个错误promise
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其它类型的
promise
封装new Promise((resolve, reject) => { resolve("成功"); }).then( result => { class Fn { then(resolve, reject){ resolve('这是对象') } } return new Fn() } ).then( result => console.log(result), reason => console.log('error ' + reason) ) // 这是对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# catch
- 可以捕获
promise
抛出的错误 - 建议统一将方法放在最后执行捕获
- 前面
then
方法做了错误回调处理,则不执行catch
方法
new Promise((resolve, reject) => {
reject("失败");
}).then(
result => console.log(result),
reason => console.log('error ' + reason)
).catch(err => {
console.log(err);
})
// error 失败
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# finally
无论状态是resolve
或 reject
都会执行此动作,finally
与状态无关。
new Promise((resolve, reject) => {
resolve("成功");
}).then(
result => console.log(result)
).catch(err => {
console.log(err);
}).finally(() => {
console.log("resolve/reject状态都会执行")
})
// 成功, resolve/reject状态都会执行
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 使用promise异步加载图片
function loadImage(src, id) {
return new Promise((resolve, reject) => {
const image = new Image()
image.src = src
image.onload = () => {
resolve(image)
}
image.onerror = reject
document.querySelector(id).appendChild(image)
})
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 定时器封装
function timeout(delay = 1000) {
return new Promise(resolve => setTimeout(resolve, delay))
}
timeout(2000).then(() => {
console.log('2秒后输出')
return timeout(1000)
}).then(() => {
console.log('再过1秒后输出')
})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 其他接口方法
# resolve
使用 promise.resolve
方法可以快速的返回一个 promise
对象
Promise.resolve("Mondo").then(value => {
console.log(value); // Mondo
});
1
2
3
2
3
缓存查询数据
function query(name) {
const cache = query.cache || (query.cache = new Map());
if (cache.has(name)) {
console.log("缓存");
return Promise.resolve(cache.get(name));
}
return ajax(`http://test.com?name=${name}`).then(
res => {
cache.set(name, response);
console.log("没走缓存");
return res;
}
);
}
query("Mondo").then(res => {
console.log(res);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# reject
和 Promise.resolve
类似,reject
生成一个失败的promise
new Promise((resolve, reject) => {
resolve('成功')
}).then(value => {
if (value !== 'mondo') {
return Promise.reject('参数错误')
}
}).catch(error => {
console.log(error) // 参数错误
})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# all
使用Promise.all
方法可以同时执行多个并行异步操作
- 任何一个
Promise
执行失败就会调用catch
方法 - 适用于一次发送多个异步操作
- 参数必须是可迭代类型,如Array/Set
- 成功后返回
promise
结果的有序数组
const p1 = new Promise((resolve, reject) => {
resolve("第一个Promise");
});
const p2 = new Promise((resolve, reject) => {
resolve("第二个Promise");
});
Promise.all([p1, p2]).then(res => {
console.log(res); // ['第一个Promise', '第二个Promise']
}).catch(error => {
console.log(error);
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# allSettled
Promise.allSettled
用于处理多个promise
,只关注执行完成,不关注是否全部执行成功,allSettled
状态只会是fulfilled
。
const p1 = new Promise((resolve, reject) => {
resolve("第一个Promise");
});
const p2 = new Promise((resolve, reject) => {
reject("第二个Promise");
});
Promise.allSettled([p1, p2]).then(res => {
console.log(res);
})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
打印出的来值为
# race
Promise.race
批量处理多个 Promise
,谁先返回状态就执行哪个
- 以最先返回的
promise
为准 - 如果最先返加的状态为
rejected
那么整个promise
为rejected
执行catch - 如果参数不是promise,内部将自动转为promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第一个Promise");
}, 1000)
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("第二个Promise");
})
});
Promise.race([p1, p2]).then(res => {
console.log(res);
}).catch(error => {
console.log(error) // 第二个Promise
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 任务队列
如果 then
返回一个 promise
时,后面的 then
就是对返回的 promise
进行处理,只有当前一个 promise
状态 resolve
后,下一个 then
方法才会执行
let promise = Promise.resolve();
let p1 = promise.then(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log(`p1`);
resolve();
}, 2000);
});
});
p1.then(() => {
return new Promise((a, b) => {
setTimeout(() => {
console.log(`p2`);
}, 1000);
});
})
// p1, p2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
实现一个队列输出
// 使用map
function queue(num) {
let promise = Promise.resolve()
num.map(v => {
promise = promise.then(_ => {
return new Promise(resolve => {
setTimeout(() => {
console.log(v)
resolve()
}, 1000)
})
})
})
}
// 使用reduce
function queue(num) {
let promise = Promise.resolve()
num.reduce((promise, v) => {
return promise.then(_ => {
return new Promise(resolve => {
setTimeout(() => {
console.log(v)
resolve();
}, 1000)
})
})
}, Promise.resolve())
}
queue([1, 2, 3, 4, 5, 6])
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
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
# async与await语法糖
# async
在函数前加上 async
,函数将返回一个 promise
,可以像使用 promise
一样使用
- 无论函数有没有返回值,
promise
状态都是resolve
完成状态
async function fn() {
return 'mondo'
}
console.log(fn())
fn().then(res => {
console.log(re)
})
1
2
3
4
5
6
7
2
3
4
5
6
7
# await
使用 await
会等待 promise
执行完
await
后面一般是promise,如果不是直接返回await
必须放在 async 定义的函数中使用await
用于替代then
使编码更优雅
async function fn() {
let promise = new Promise(resolve => {
setTimeout(() => {
resolve('mondo')
}, 1000)
})
let a = await promise
console.log(a)
}
fn()
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# async 延时函数
async function sleep(delay = 2000) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, delay)
})
}
async function show(arr) {
for (const v of arr) {
await sleep()
console.log(v)
}
}
show([1, 2])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# class 与 await 的结合
class User {
constructor(name) {
this.name = name
}
// 定义then方法,返回 resolve 状态
then(resolve, reject) {
setTimeout(() => {
resolve(this.name)
}, 1000)
}
}
async function get() {
let user = await new User('mondo')
console.log(user)
}
get() // mondo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# async 错误处理
使用
catch
捕获错误async function fn() { throw new Error('error') } fn().catch(err => { console.log(err) })
1
2
3
4
5
6使用
try...catch
捕获错误async function fn() { try { const a = await fn1() const b = await fn2() return b } catch (error => { console.log(error) }) } fn()
1
2
3
4
5
6
7
8
9
10
# await 并行执行
async function p1() {
return 'mondo'
}
async function p2() {
return 'imondo.cn'
}
async function fn() {
const h1 = p1()
const h2 = p2()
console.log(h1, h2)
const v1 = await h1
const v2 = await h2
console.log(v1, v2)
}
fn() // 同时打印 mondo imondo.cn
// 或者
async function fn1() {
const res = await Promise.all([p1(), p2()])
console.log(res)
}
fn1() // 同时打印 ['mondo', 'imondo.cn']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 宏任务与微任务执行顺序
同步任务优先执行
微任务优先宏任务执行
微任务
promise
宏任务
setTimeout
setTimeout(() => {
console.log(1)
}, 0)
new Promise(reslove => {
reslove()
console.log(2)
}).then(() => {
console.log(3')
})
console.log(4) // 2,4,3,1
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 手写一个Promise
- 实现promise基本用法
- 实现then链式调用方法
- 实现all方法
- 实现race方法
class MoPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECT = "reject";
constructor(executor) {
this.status = MoPromise.PENDING;
this.value = null;
this.callbacks = [];
// 出现异常时执行reject方法
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
// 只有pending状态下才执行,且状态变了后不可修改
if (this.status === MoPromise.PENDING) {
this.status = MoPromise.FULFILLED;
this.value = value;
setTimeout(() => {
this.callbacks.map(callback => {
callback.onFulfilled(value);
});
});
}
}
reject(reason) {
if (this.status === MoPromise.PENDING) {
this.status = MoPromise.REJECT;
this.value = reason;
setTimeout(() => {
this.callbacks.map(callback => {
callback.onReject(reason);
});
});
}
}
then(onFulfilled, onReject) {
// 当回调函数没传时,定义默认函数
if (typeof onFulfilled !== "function") {
onFulfilled = () => this.value; // then穿透传值
}
if (typeof onReject !== "function") {
onReject = () => this.value;
}
// 返回promise,实现链式操作
let promise = new MoPromise((resolve, reject) => {
// 准备状态处理,以后需要执行的任务队列
if (this.status === MoPromise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse(promise, onFulfilled(value), resolve, reject);
},
onReject: value => {
this.parse(promise, onReject(value), resolve, reject);
}
});
}
// 只有状态改变 才执行方法
if (this.status === MoPromise.FULFILLED) {
// 放置在任务队列,实现异步操作
setTimeout(() => {
this.parse(promise, onFulfilled(this.value), resolve, reject);
});
}
if (this.status === MoPromise.REJECT) {
setTimeout(() => {
this.parse(promise, onReject(this.value), resolve, reject);
});
}
});
return promise;
}
parse(promise, result, resolve, reject) {
if (promise === result) {
throw new TypeError("不可返回相同类型");
}
try {
// 如果then返回promise
if (result instanceof MoPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
static resolve(value) {
return new MoPromise((resolve, reject) => {
if (value instanceof MoPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(value) {
return new MoPromise((resolve, reject) => {
if (value instanceof MoPromise) {
value.then(resolve, reject);
} else {
reject(value);
}
});
}
static all(promises) {
const values = [];
return new MoPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(
value => {
values.push(value);
if (values.length === promises.length) {
resolve(values);
}
},
reason => {
reject(reason);
}
);
});
});
}
static race(promises) {
return new MoPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(
value => {
resolve(value);
},
reason => {
reject(reason);
}
);
});
});
}
}
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
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