简单实现一个Promise

简单实现一个Promise A+ 规范的Promise

首先,了解一下Promise的基本用法

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const promise = new Promise((resolve, reject) => {
if() {
resolve('成功回调')
}else{
reject('失败回调')
}
});

promise.then(res => {
console.log('成功回调')
}, err => {
console.log('失败回调')
})

通过上述用法,可以看出来Promise 接受一个执行器函数作为参数,这个函数带有两个参数

  • resolve:把 Promise 状态改成成功
  • reject:把 Promise 状态改成失败

promise的状态有三种,分别是:

  • pending 默认状态
  • fulfilled 成功,返回成功值
  • rejected 失败,返回失败值

promise的状态是单向流动的,且一旦成功和失败,状态不可改变

下面我们可以简单实现一下基本特性

COPY
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

const STATUS = {
PENDING: 'pending',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}

class MyPromise {
construtor(executor) {
// 执行器
executor(this.resolve, this.reject)
}

// 初始状态
status = STATUS.PENDING

// 成功结果
value = null;

// 失败结果
reason = null;

// 成功
resolve = value => {
// 单向状态变更
if(this.status == STATUS.PENDING){
this.status = STATUS.fulfilled;
this.value = value;
}
}

// 失败
reject = reason => {
// 单向状态变更
if(this.status == STATUS.PENDING){
this.status = STATUS.REJECTED;
this.reason = reason;
}
}

}

除此之外,Promise.then 还分别接收两个回调

COPY
1
Promise.then(onFulfilled, onRejected);

其中
onFulfilled 要求如下:

  • 必须在 promise 状态为完成时调用它,并将 promise 的 value 作为它的第一个参数
  • 在 promise 完成之前不能调用它
  • 它不能被多次调用

onRejected 要求如下:

  • 必须在 promise 被拒绝后调用它,以 promise.reason 作为它的第一个参数
  • 在 promise 被拒绝之前不能调用它
  • 它不能被多次调用

于是我们继续补充 MyPromise

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
class MyPromise {
...
...
then(onFulfilled, onRejected){
if(this.status == STATUS.FULFILLED){
// 确保当前是 FULFILLED 状态
onFulfilled(this.value);
}else if(this.status == STATUS.REJECTED){
// 确保当前是 REJECTED 状态
onRejected(this.reason);
}
}
}

至此 一个简单的 MyPromise 就完成了
实验一下

COPY
1
2
3
4
5
6
7
8
9
10
const mypromise = new MyPromise((resolve, reject) => {
resolve('成功')
})

mypromise.then(data => {
console.log(data, '请求成功') // 成功打印“成功 请求成功”
}, err => {
console.log(err, '请求失败')
})

成功了

接着,根据 Promise A+ 规范继续完善 MyPromise.then

2.2.1 Both onFulfilled and onRejected are optional arguments:
2.2.1.1 If onFulfilled is not a function, it must be ignored.
2.2.1.2 If onRejected is not a function, it must be ignored.

简单说,就是 Promise.then 接受的 onFulfilledonRejected 是可选的。如果 onFulfilled 不是函数,他必须被忽略。如果 onRejected 不是函数,也必须被忽略。

那么,我们在这里加个判断

COPY
1
2
3
4
5
6
7
8
9
10
class MyPromise {
...
...
then(onFulfilled, onRejected){

onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value

onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error }
}
}

then 可以在同一个承诺上多次调用

  • 当 promise 完成,所有相应的 onFulfilled 回调必须按照它们的原始调用的顺序执行 then
  • 当 promise 被拒绝,所有相应的 onRejected 回调必须按照它们对 的原始调用的顺序执行 then

可以理解为将 onFulfilled、onRejected 作为数组存储在 MyPromise 中,然后按照顺序执行

如下图,新增了成功回调跟失败回调

COPY
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
class MyPromise {
// 成功回调
onFulfilledCallback = []

// 失败回调
onRejectedCallback = []

// 修改 Promise 状态,并定义成功返回值
resolve = value => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FULFILLED
this.value = value

while(this.onFulfilledCallback.length) {
this.onFulfilledCallback.shift()(value)
}
}
}

// 修改 Promise 状态,并定义失败返回值
reject = value => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED
this.reason = value

while(this.onRejectedCallback.length) {
this.onRejectedCallback.shift()(value)
}
}
}

then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
if (this.status === STATUS.PENDING) {
this.onFulfilledCallback.push(onFulfilled)
this.onRejectedCallback.push(onRejected)
} else if (this.status === STATUS.FULFILLED) {
onFulfilled(this.value)
} else if (this.status === STATUS.REJECTED) {
onRejected(this.reason)
}
}
}

then 必须返回一个 Promise 来支持链式调用 Promise

  • then 方法需要返回 MyPromise 实例
  • then 内部调用回调时,需通过 resolvePromise 方法判断返回值 x 的类型来处理返回值
COPY
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
class MyPromise {
then = function (onFulfilled, onRejected) {
// 返回 MyPromise 实例
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === STATUS.PENDING) {
const value = onFulfilled(this.value)
this.onFulfilledCallback.push(() => {
resolvePromise(promise2, value, resolve, reject)
})

const reason = onRejected(this.value)
this.onRejectedCallback.push(() => {
resolvePromise(promise2, reason, resolve, reject)
})
} else if (this.status === STATUS.FULFILLED) {
const value = onFulfilled(this.value)
resolvePromise(promise2, value, resolve, reject)
} else if (this.status === STATUS.REJECTED) {
const error = onRejected(this.error)
resolvePromise(promise2, error, resolve, reject)
}
})

return promise2
}
}

上述代码引用了 resolvePromise 来处理 Promise.then 的返回值

  • 如果 promise2 === x, 执行 reject,错误原因为 TypeError
  • 如果 x 是函数或对象
    • 如果 x.then 是函数
      • 执行 x.then
    • 如果 x.then 不是函数
      • 执行 resolve(x)
  • 如果 x 不是函数或对象
    • 执行 resolve(x)
COPY
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
function resolvePromise (promise2, x, resolve, reject) {
// 如果 promise2 === x, 执行 reject,错误原因为 TypeError
if (promise2 === x) {
reject(new TypeError('The promise and the return value are the same'))
}

// 如果 x 是函数或对象
if (typeof x === 'object' || typeof x === 'function') {
let then
try {
then = x.then
} catch (error) {
reject(error)
}

// 如果 x.then 是函数
if (typeof then === 'function') {
then.call(x, y => {
// resolve的结果依旧是promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
reject(err);// 失败了
})
} else {
// 如果 x.then 不是函数
resolve(x)
}
} else {
// 如果 x 不是 promise 实例
resolve(x)
}
}

好了

作者: 果汁
文章链接: https://guozhigq.github.io/post/a92be253.html
版权声明: All posts on this blog are licensed under the CC BY-NC-SA 4.0 license unless otherwise stated. Please cite 果汁来一杯 !