实现一个符合 Promises/A+ 规范的 Promise

4/1/2024 js

基于官方Promises/A+规范,实现一个符合Promises/A+规范的Promise

# 编写代码

// promise.js
function Promise(executor) {

  this.state = "pending";
  this.onFulfilledCallback = [];
  this.onRejectedCallback = [];

  const self = this;

  function resolve(value) {
    setTimeout(function () {
      if (self.state === "pending") {
        self.state = 'fulfilled';
        self.data = value;
        for (let i = 0; i < self.onFulfilledCallback.length; i++) {
          self.onFulfilledCallback[i](value);
        }
      }
    });
  }

  function reject(reason) {
    setTimeout(function () {
      if (self.state === 'pending') {
        self.state = 'rejected';
        self.data = reason;
        for (let i = 0; i < self.onRejectedCallback.length; i++) {
          self.onRejectedCallback[i](reason);
        }
      }
    });
  }

  try {
    executor(resolve, reject);
  } catch (reason) {
    reject(reason);
  }
}

Promise.prototype.then = function (onFulfilled, onRejected) {
  const self = this;

  let promise2;

  return (promise2 = new Promise(function (resolve, reject) {
    if (self.state === 'fulfilled') {
      setTimeout(function () {
        if (typeof onFulfilled === 'function') {
          try {
            const x = onFulfilled(self.data);
            promiseResolutionProcedure(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        } else {
          resolve(self.data);
        }
      })
    } else if (self.state === 'rejected') {
      setTimeout(function () {
        if (typeof onRejected === 'function') {
          try {
            const x = onRejected(self.data);
            promiseResolutionProcedure(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        } else {
          reject(self.data);
        }
      })
    } else if (self.state === 'pending') {
      self.onFulfilledCallback.push(function (promise1Value) {
        if (typeof onFulfilled === 'function') {
          try {
            const x = onFulfilled(self.data);
            promiseResolutionProcedure(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        } else {
          resolve(promise1Value);
        }
      });

      self.onRejectedCallback.push(function (promise1Reason) {
        if (typeof onRejected === 'function') {
          try {
            const x = onRejected(self.data);
            promiseResolutionProcedure(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        } else {
          reject(promise1Reason);
        }
      })

    }

  }))
}

function promiseResolutionProcedure(promise2, x, resolve, reject) {

  if (promise2 === x) {
    return reject(new TypeError("Chaining cycle detected for promise"));
  }

  if (x instanceof Promise) {
    if (x.state === 'pending') {
      x.then(function (value) {
        promiseResolutionProcedure(promise2, value, resolve, reject);
      }, reject);
    } else if (x.state === 'fulfilled') {
      resolve(x.data);
    } else if (x.state === 'rejected') {
      reject(x.data);
    }
    return;
  }

  if (x && (typeof x === 'object' || typeof x === 'function')) {
    let isCalled = false;
    try {
      let then = x.then;

      if (typeof then === 'function') {
        then.call(
          x,
          function resolvePromise(y) {
            if (isCalled) return;
            isCalled = true;
            return promiseResolutionProcedure(promise2, y, resolve, reject);
          },
          function rejectPromise(r) {
            if (isCalled) return;
            isCalled = true;
            return reject(r);
          }
        )
      } else {
        resolve(x);
      }
    } catch (e) {
      if (isCalled) return;
      isCalled = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

module.exports = 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
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
151
152
153
154
155
156
157

# 测试代码


// test.js

// 导入我们写好的 promise
const Promise = require("./promise.js");

// 根据官方文档暴露一个 deferred 方法,返回一个包含 promise、resolve、reject 的对象
Promise.deferred = function () {
  const obj = {};

  obj.promise = new Promise(function (resolve, reject) {
    obj.resolve = resolve;
    obj.reject = reject;
  });

  return obj;
};

module.exports = Promise;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

执行命令查看测试覆盖率

npx promises-aplus-tests test.js
1