001 Promise
CENSWIN 7/17/2021 Javascript
promise 技术方案的出现是为了解决原来的回调地狱,举例我们需要在淘宝买一样东西那么流程如下:
- 查找商品
- 找到了进行购买生成订单
- 付款
- 付款成功
那么用ajax请求写出来会如何呢
url: "/api/searchGoods?name="iphone""
success: function (res) {
if (res.code === 200) { // 找到了
$.ajax({
url: "/api/buy?id="88"", // 去生成订单
success: function (res) {
if (res.code === 200) { // 生成订单合法
$.ajax({
url: 'api/pay?billid="123"', // 付款
success: function (res) {
if (res.code === 200) { // 付款成功
alert('付款成功')
}
}
})
}
}
})
}
}
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
怎么样是不是晕了,如果这个流程需要10个步骤或者20个步骤呢?或者我们可以将成功后的回调函数写到函数体外,用函数名来进行调用,但是并没有什么作用,当我们的大脑进行线性思考的时候不得不在各个函数之间反复横跳。且 如果中间某一步出错他也并不会移动到一个处理错误的函数上。
那么就需要promise登场了,promise 是一个对象,promise 有三种状态 “pending”、“fulfiled”、“rejected”,状态一旦改变就不会再变,一旦new promise 它会立即执行,promise接收一个函数作为参数,函数需要传入两个值(res, rej)(由promise提供,用该改变promise对象中的值)
const p = new promise((res,rej) => {
...........
})
1
2
3
2
3
意思就是 promise 会给这个函数提供一个res和rej函数用来改变对象的值,当请求完成即可调用对应函数修改对象,后续就可以使用then方法获取对应值。我们将上面的ajax用promise进行优化
function req (url) {
return new Promise((res, rej) => {
$.ajax({
url: url,
success: function (data) {
if (data.code === 200) {
res(data); // 此时res方便就改变了promise对象中的value值
} else {
rej(data.msg) // 如果失败则改变promise对象的error值
}
}
})
})
}
req("/api/searchGoods?name="iphone"").then(value => {
return req("/api/buy?id="88"")
}, error => console.log(error)).then(value => {
return req('api/pay?billid="123"')
}, error => console.log(error)).then(value => {
alert('付款成功')
}, error => console.log(error)).catch(error => {
console.log(error)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
最后的这个catch是用来接收异常的,一旦有哪一步出错都会被该方法接收,避免了报错卡死
简单实现promise
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
try{
executor(this.resolve, this.reject)
} catch(error) {
this.reject(error)
}
}
status = PENDING
value = null
reason = null
onFulfilledCallbacks = []
onRejectedCallbacks = []
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(value)
}
}
}
reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(reason)
}
}
}
then(onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject, setName) => {
setName('promise2');
if (this.status === FULFILLED) {
queueMicrotask(() => {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
})
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
})
return promise2
}
}
function resolvePromise(promise2,x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
export default MyPromise
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
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