# Promise/A+

ES6 的 Promise,相信很多人都知道。如果是在 ES5 呢?你如何自己实现一个 Promise?

ES6 采用的是 Promise/A+ 规范,那么也采用一样的规范。Promise/A+规范原文(英文) (opens new window),翻译的话,网上比较多,可以参考这篇翻译(中文) (opens new window)

# 准备

使用promises-aplus-tests (opens new window)插件进行测试是否符合Promise/A+规范。

npm install promises-aplus-tests -D
1

# 构造函数

// 等待态
const PENDING = "pending";
// 执行态
const FULFILLED = "fulfilled";
// 拒绝态
const REJECTED = "rejected";

class XPromise {
  constructor(fn) {
    // 状态
    this.state = PENDING;
    // 终值
    this.value = undefined;
    // 拒因
    this.reason = undefined;
    // 执行回调队列
    this.onFulfilledCallbacks = [];
    // 拒绝回调队列
    this.onRejectedCallbacks = [];

    // 执行的方法
    const resolve = (value) => {
      // 需要异步,这里使用宏任务
      setTimeout(() => {
        if (this.state === PENDING) {
          this.state = FULFILLED;
          this.value = value;
          // 等待态->执行态
          // 需要调用执行回调队列的所有方法
          this.onFulfilledCallbacks.forEach((f) => f(this.value));
        }
      });
    };

    // 拒绝的方法
    const reject = (reason) => {
      // 需要异步,这里使用宏任务
      setTimeout(() => {
        if (this.state === PENDING) {
          this.state = REJECTED;
          this.reason = reason;
          // 等待态->拒绝态
          // 需要调用拒绝回调队列的所有方法
          this.onRejectedCallbacks.forEach((f) => f(this.reason));
        }
      });
    };

    // 如果报错,就调用拒绝方法
    try {
      fn(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
}
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

# then 方法

2.2.1、2.2.2、2.2.3 的实现。

class XPromise {
  //...

  then(onFulfilled, onRejected) {
    // 2.2.1.1 不是函数就忽略
    if (typeof onFulfilled !== "function") return;
    // 2.2.1.2 不是函数就忽略
    if (typeof onRejected !== "function") return;

    // 这里已经确保了onFulfilled,onRejected是函数了,也满足了2.2.2,2.2.3

    // 2.2.2,2.2.3 就把方法添加到队列里,promise完成后会自动调用
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(onFulfilled);
      this.onRejectedCallbacks.push(onRejected);
    }

    // 2.2.2 如果promise完成了,就直接调用
    if (this.state === FULFILLED) onFulfilled(this.value);

    // 2.2.3 如果promise完成了,就直接调用
    if (this.state === REJECTED) onRejected(this.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

2.2.4 关于事件循环问题,这里用异步中的宏任务

















 

 




 

 




class XPromise {
  //...

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== "function") return;
    if (typeof onRejected !== "function") return;

    if (this.state === PENDING) {
      // 2.2.4 为什么这里不用加?
      // 你仔细看看XPromise构造函数,遍历调用前有没有包裹类似的东西?
      this.onFulfilledCallbacks.push(onFulfilled);
      this.onRejectedCallbacks.push(onRejected);
    }

    if (this.state === FULFILLED) {
      // 2.2.4 事件循环 这里也用setTimeout异步的宏任务
      setTimeout(() => {
        onFulfilled(this.value);
      });
    }

    if (this.state === REJECTED) {
      // 2.2.4 事件循环 这里也用setTimeout异步的宏任务
      setTimeout(() => {
        onRejected(this.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

2.2.7 需要返回一个promise,意味着 2.2.1 要用另一种方式实现。






 









 


 



 


 




 


 




 



class XPromise {
  //...

  then(onFulfilled, onRejected) {
    // *文档的promise2就是返回的promise,promise1就是自身
    let promise;

    // 需要返回 Promise
    // if (typeof onFulfilled !== "function") return;
    // if (typeof onRejected !== "function") return;

    const isFunFulfilled = typeof onFulfilled === "function";
    const isFunRejected = typeof onRejected === "function";

    if (this.state === PENDING) {
      promise = new Promise(() => {
        if (isFunFulfilled) this.onFulfilledCallbacks.push(onFulfilled);
        if (isFunRejected) this.onRejectedCallbacks.push(onRejected);
      });
    }

    if (this.state === FULFILLED) {
      promise = new Promise(() => {
        setTimeout(() => {
          if (isFunFulfilled) onFulfilled(this.value);
        });
      });
    }

    if (this.state === REJECTED) {
      promise = new Promise(() => {
        setTimeout(() => {
          if (isFunRejected) onRejected(this.reason);
        });
      });
    }

    // 因为state只用3种状态,所以以上三个代表快会有一个执行,必然会返回promise
    return 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

2.2.7.1 如果onFulfilledonRejected返回一个值x,请运行 Promise 解决程序[[Resolve]](promise2, x)














 
 





 
 









 
 









 
 










 



class XPromise {
  //...

  then(onFulfilled, onRejected) {
    let promise;

    const isFunFulfilled = typeof onFulfilled === "function";
    const isFunRejected = typeof onRejected === "function";

    if (this.state === PENDING) {
      promise = new Promise((resolve, reject) => {
        if (isFunFulfilled) {
          this.onFulfilledCallbacks.push((value) => {
            const x = onFulfilled(value);
            ResolutionProcedure(promise, x, resolve, reject);
          });
        }

        if (isFunRejected) {
          this.onRejectedCallbacks.push((reason) => {
            const x = onRejected(reason);
            ResolutionProcedure(promise, x, resolve, reject);
          });
        }
      });
    }

    if (this.state === FULFILLED) {
      promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          if (isFunFulfilled) {
            const x = onFulfilled(this.value);
            ResolutionProcedure(promise, x, resolve, reject);
          }
        });
      });
    }

    if (this.state === REJECTED) {
      promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          if (isFunRejected) {
            const x = onRejected(this.reason);
            ResolutionProcedure(promise, x, resolve, reject);
          }
        });
      });
    }

    return promise;
  }
}

// Promise 解决程序,为了方便。promise的resolve, reject方法一起传过来
function ResolutionProcedure(promise, x, resolve, reject) {
  // 等会会讲到
}
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

2.2.7.2 如果onFulfilledonRejected抛出一个异常epromise2必须拒绝并将e作为reason














 


 
 
 





 


 
 
 








 




 
 
 







 




 
 
 








class XPromise {
  //...

  then(onFulfilled, onRejected) {
    let promise;

    const isFunFulfilled = typeof onFulfilled === "function";
    const isFunRejected = typeof onRejected === "function";

    if (this.state === PENDING) {
      promise = new Promise((resolve, reject) => {
        if (isFunFulfilled) {
          this.onFulfilledCallbacks.push((value) => {
            try {
              const x = onFulfilled(value);
              ResolutionProcedure(promise, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        }

        if (isFunRejected) {
          this.onRejectedCallbacks.push((reason) => {
            try {
              const x = onRejected(reason);
              ResolutionProcedure(promise, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        }
      });
    }

    if (this.state === FULFILLED) {
      promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            if (isFunFulfilled) {
              const x = onFulfilled(this.value);
              ResolutionProcedure(promise, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    }

    if (this.state === REJECTED) {
      promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            if (isFunRejected) {
              const x = onRejected(this.reason);
              ResolutionProcedure(promise, x, resolve, reject);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    }

    return 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
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

2.2.7.3、2.2.7.4 又是关于onFulfilledonRejected是否函数问题。需要和 2.2.1 结合一下。












 


 






 






 


 



 








 




 




 








 




 



 












class XPromise {
  //...

  then(onFulfilled, onRejected) {
    let promise;

    const isFunFulfilled = typeof onFulfilled === "function";
    const isFunRejected = typeof onRejected === "function";

    if (this.state === PENDING) {
      promise = new Promise((resolve, reject) => {
        this.onFulfilledCallbacks.push((value) => {
          try {
            // 是否函数判断、写到里面一层
            if (isFunFulfilled) {
              const x = onFulfilled(value);
              ResolutionProcedure(promise, x, resolve, reject);
            } else {
              // 在构造函数里,如果状态完成或失败了,会执行相应的回调队列。
              // 在这个方法内部,肯定是状态完成了,才执行的。
              // 而且value也是this.value
              resolve(value);
            }
          } catch (e) {
            reject(e);
          }
        });

        this.onRejectedCallbacks.push((reason) => {
          try {
            // 与上面同理
            if (isFunRejected) {
              const x = onRejected(reason);
              ResolutionProcedure(promise, x, resolve, reject);
            } else {
              reject(reason);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    }

    if (this.state === FULFILLED) {
      promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            // 是否函数判断、写到里面一层
            if (isFunFulfilled) {
              const x = onFulfilled(this.value);
              ResolutionProcedure(promise, x, resolve, reject);
            } else {
              // 看看45行,状态是完成的了
              resolve(this.value);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    }

    if (this.state === REJECTED) {
      promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            // 与上面同理
            if (isFunRejected) {
              const x = onRejected(this.reason);
              ResolutionProcedure(promise, x, resolve, reject);
            } else {
              reject(this.reason);
            }
          } catch (e) {
            reject(e);
          }
        });
      });
    }

    return 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
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

# Promise 解决程序

你可以理解成,处理新的promise2和上一个的promise1onFulfilled返回值x的关系。(不懂的话,看看下面)

# 理解

解决程序是干什么用的?先来看看下面的例子,v2就是onFulfilled的返回值吗?

const promise1 = new Promise((resolve) => resolve(1));
// const promise2 = promise1.then(onFulfilled, onRejected)
const promise2 = promise1.then((v1) => v1 + 2);
const promise3 = promise2.then((v2) => {
  console.log(v2); // 3
});
1
2
3
4
5
6

如果返回一个Promise,或者 thenable(带有then属性的对象)类型?还是原模原样打印出吗?

const promise1 = new Promise((resolve) => resolve(1));
const promise2 = promise1.then((v1) => {
  const x = new Promise((resolve) => {
    setTimeout(() => resolve(v1 - 1), 2000);
  });
  return x; // 返回一个Promise
});
const promise3 = promise2.then((v2) => {
  // 明显不是打印[Promise]结构体出来,而是一个数字。而且需要更长的时间才显示。
  console.log(v2); // 0
});
1
2
3
4
5
6
7
8
9
10
11

# 实现

2.3.1、2.3.2 的实现。

function ResolutionProcedure(promise, x, resolve, reject) {
  // 2.3.1 如果promise和x引用同一个对象,则用TypeError作为reason拒绝promise
  if (promise === x) {
    reject(new TypeError("循环引用"));
    return;
  }

  // 2.3.2
  if (x instanceof XPromise) {
    switch (x.state) {
      // 2.3.2.1 如果x为pending状态,promise必须保持pending状态直到x成功或者失败
      case PENDING:
        // x.then(resolve, reject);
        // 这里为什么不是上一行?你回想上面的理解,就是为了处理返回值的类型。
        // 如果是x.then(resolve, reject),就等于没处理了,所以需要调用解决程序方法。
        x.then((value) => {
          ResolutionProcedure(promise, value, resolve, reject);
        }, reject);
        break;
      // 2.3.2.2 如果x为完成状态,用相同的值完成promise
      case FULFILLED:
        resolve(x.value);
        break;
      // 2.3.2.3 如果x为失败状态,用相同的reason拒绝promise
      case REJECTED:
        reject(x.reason);
        break;
    }
  }
}
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

2.3.3、2.3.3.1、2.3.3.2 的实现。





















 
 
 
 
 
 
 
 
 
 


function ResolutionProcedure(promise, x, resolve, reject) {
  if (promise === x) {
    reject(new TypeError("循环引用"));
    return;
  }

  if (x instanceof XPromise) {
    switch (x.state) {
      case PENDING:
        x.then((value) => {
          ResolutionProcedure(promise, value, resolve, reject);
        }, reject);
        break;
      case FULFILLED:
        resolve(x.value);
        break;
      case REJECTED:
        reject(x.reason);
        break;
    }
  } else if (x && ["object", "function"].includes(typeof x)) {
    // 2.3.3 如果x是一个对象或函数
    try {
      // 2.3.3.1 让then为x.then
      const then = x.then;
    } catch (e) {
      // 2.3.3.2 如果检索属性x.then的结果抛出一个异常e,用e作为reason拒绝promise
      reject(e);
    }
  }
}
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

2.3.3.3、2.3.3.3.1、2.3.3.3.2 的实现

























 
 
 
 
 
 
 
 
 
 
 
 
 
 






function ResolutionProcedure(promise, x, resolve, reject) {
  if (promise === x) {
    reject(new TypeError("循环引用"));
    return;
  }

  if (x instanceof XPromise) {
    switch (x.state) {
      case PENDING:
        x.then((value) => {
          ResolutionProcedure(promise, value, resolve, reject);
        }, reject);
        break;
      case FULFILLED:
        resolve(x.value);
        break;
      case REJECTED:
        reject(x.reason);
        break;
    }
  } else if (x && ["object", "function"].includes(typeof x)) {
    try {
      const then = x.then;

      if (typeof then === "function") {
        // 2.3.3.3.1
        const resolvePromise = (y) => {
          ResolutionProcedure(promise, y, resolve, reject);
        };

        // 2.3.3.3.2
        const rejectPromise = (r) => {
          reject(r);
        };

        // 2.3.3.3 指针替换
        then.call(x, resolvePromise, rejectPromise);
      }
    } catch (e) {
      reject(e);
    }
  }
}
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

2.3.3.3.3 的实现。






















 





 
 




 
 






 
 





function ResolutionProcedure(promise, x, resolve, reject) {
  if (promise === x) {
    reject(new TypeError("循环引用"));
    return;
  }

  if (x instanceof XPromise) {
    switch (x.state) {
      case PENDING:
        x.then((value) => {
          ResolutionProcedure(promise, value, resolve, reject);
        }, reject);
        break;
      case FULFILLED:
        resolve(x.value);
        break;
      case REJECTED:
        reject(x.reason);
        break;
    }
  } else if (x && ["object", "function"].includes(typeof x)) {
    let firstRun = false;
    try {
      const then = x.then;

      if (typeof then === "function") {
        const resolvePromise = (y) => {
          if (firstRun) return;
          firstRun = true;
          ResolutionProcedure(promise, y, resolve, reject);
        };

        const rejectPromise = (r) => {
          if (firstRun) return;
          firstRun = true;
          reject(r);
        };

        then.call(x, resolvePromise, rejectPromise);
      }
    } catch (e) {
      if (firstRun) return;
      firstRun = true;
      reject(e);
    }
  }
}
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

2.3.3.4、2.3.4 的实现。









































 







 



function ResolutionProcedure(promise, x, resolve, reject) {
  if (promise === x) {
    reject(new TypeError("循环引用"));
    return;
  }

  if (x instanceof XPromise) {
    switch (x.state) {
      case PENDING:
        x.then((value) => {
          ResolutionProcedure(promise, value, resolve, reject);
        }, reject);
        break;
      case FULFILLED:
        resolve(x.value);
        break;
      case REJECTED:
        reject(x.reason);
        break;
    }
  } else if (x && ["object", "function"].includes(typeof x)) {
    let firstRun = false;
    try {
      const then = x.then;

      if (typeof then === "function") {
        const resolvePromise = (y) => {
          if (firstRun) return;
          firstRun = true;
          ResolutionProcedure(promise, y, resolve, reject);
        };

        const rejectPromise = (r) => {
          if (firstRun) return;
          firstRun = true;
          reject(r);
        };

        then.call(x, resolvePromise, rejectPromise);
      } else {
        resolve(x); // 2.3.3.4 如果then不是函数,用x来完成promise
      }
    } catch (e) {
      if (firstRun) return;
      firstRun = true;
      reject(e);
    }
  } else {
    resolve(x); // 2.3.4 如果x不是对象或者函数,用x来完成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
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

# 测试

根据promises-aplus-tests (opens new window)文档,加入以下内容。

XPromise.deferred = function() {
  var result = {};
  result.promise = new XPromise(function(resolve, reject) {
    result.resolve = resolve;
    result.reject = reject;
  });

  return result;
};

module.exports = XPromise;
1
2
3
4
5
6
7
8
9
10
11
// package.json
{
  // ...
  "main": "promise.js",
  "scripts": {
    "test": "promises-aplus-tests ./promise.js"
  },
  "devDependencies": {
    "promises-aplus-tests": "^2.1.2"
  }
}
1
2
3
4
5
6
7
8
9
10
11

测试结果:官方 872 个例子全部通过。 测试结果