手写 Promise

手写 Promise

1. Promise 的基本特征:

  1. promise 有三个状态:pending,fulfilled,or rejected;「规范 Promise/A+ 2.1」
  2. new promise时, 需要传递一个executor()执行器,执行器立即执行;
  3. executor接受两个参数,分别是resolve和reject;.
  4. promise 的默认状态是 pending;
  5. promise 有一个value保存成功状态的值,可以是undefined/thenable/promise;「规范 Promise/A+ 1.3」
  6. promise 有一个reason保存失败状态的值;「规范 Promise/A+ 1.5」
  7. promise 只能从pending到rejected, 或者从pending到fulfilled,状态一旦确认,就不会再改变;
  8. promise 必须有一个then方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected;「规范 Promise/A+ 2.2」
  9. 如果调用 then 时,promise 已经成功,则执行onFulfilled,参数是promise的value;
  10. 如果调用 then 时,promise 已经失败,那么执行onRejected, 参数是promise的reason;
  11. 如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个 then 的失败的回调onRejected;

2. 简单实现

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
// 三个状态:PENDING、FULFILLED、REJECTED
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise {
constructor(executor) {
// 默认状态为 PENDING
this.status = PENDING;
// 存放成功状态的值,默认为 undefined
this.value = undefined;
// 存放失败状态的值,默认为 undefined
this.reason = undefined;

// 调用此方法就是成功
let resolve = (value) => {
// 状态为 PENDING 时才可以更新状态,防止 executor 中调用了两次 resovle/reject 方法
if(this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}

// 调用此方法就是失败
let reject = (reason) => {
// 状态为 PENDING 时才可以更新状态,防止 executor 中调用了两次 resovle/reject 方法
if(this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}

try {
// 立即执行,将 resolve 和 reject 函数传给使用者
executor(resolve,reject)
} catch (error) {
// 发生异常时执行失败逻辑
reject(error)
}
}

// 包含一个 then 方法,并接收两个参数 onFulfilled、onRejected
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}

if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}

3. 测试

1
2
3
4
5
6
7
8
9
10
const promise = new Promise((resolve, reject) => {
resolve('成功');
}).then(
(data) => {
console.log('success', data)
},
(err) => {
console.log('faild', err)
}
)
You forgot to set the qrcode for Alipay. Please set it in _config.yml.
You forgot to set the qrcode for Wechat. Please set it in _config.yml.
You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×