# 手写 Promise

# Promise A+ 规范

# 1. 术语 Terminology

  1. Promise: 是一个有then方法的函数或者对象, then方法遵循Promise A+规范
  2. thenable: 是一个定义了then方法的对象或者函数
  3. value是一个合法的js值(包括 undefined thenable promise)
  4. 异常(exception): 使用throw语句抛出的一个值
  5. 原因(reason): 表示promise为什么被拒绝的一个值

# 2. 必要条件 Requirements

# 2.1 Promise状态

promise必须是这三个状态中的一种:等待态pending,解决态fulfilled或拒绝态rejected

  • # 2.1.1 当promise是等待(pending 状态 的时候 :
    • # 2.1.1.1 可能变为解决或者拒绝状态。
# 2.1.2 当一个promise处于解决(fulfilled)状态的时候 :
  • # 2.1.2.1 一定不能转换为任何其它状态
  • # 2.1.2.2. 必须有一个不能改变的值
# 2.1.3. 当一个promise处于拒绝(rejected)状态的时候:
  • # 2.1.3.1. 一定不能转换为任何其它状态
  • # 2.1.3.2. 必须有一个不能改变的值

在这里,"一定不能改变"意味着不变的身份(例如 ===),但是并不意味着深度不可变性。(译注者:这里应该是说只要值的引用相同即可,并不需要引用中的每一个值都相等)

# 2.2. then 方法

Promise必须提供一个then方法来访问当前或最终的值或原因。

Promise的then方法接受俩个参数:

promise.then(onFulfilled, onRejected)

  • # 2.2.1 onFulfilled 和 onRejected 这俩参数都是可选的
    • # 2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
    • # 2.2.1.2. 如果onRejected不是一个函数,它必须被忽略
  • # 2.2.2. 如果onFulfilled是一个函数
    • # 2.2.2.1. 它必须在promise被解决后调用,promise的值作为它的第一个参数。
    • # 2.2.2.2 它一定不能在promise被解决前调用。
    • # 2.2.2.3 它一定不能被调用多次。
  • # 2.2.3. 如果onRejected是一个函数
    • # 2.2.3.1 它必须在promise被拒绝之后调用,用promise的原因作为它的第一个参数。
    • # 2.2.3.2 它一定不能在promise被拒绝之前调用。
    • # 2.2.3.3 它一定不能被调用多次。
  • # 2.2.4. 在执行上下文栈中只包含平台 (opens new window)代码之前,onFulfilled或onRejected一定不能被调用 [3.1]
  • # 2.2.5. onFulfilled和onRejected一定被作为函数调用(没有this值) [3.2]
  • # 2.2.6. 同一个promise上的then可能被调用多次
    • # 2.2.6.1. 如果promise被解决,所有相应的onFulfilled回调必须按照他们原始调用then的顺序执行
    • # 2.2.6.2. 如果promise被拒绝,所有相应的onRejected回调必须按照他们原始调用then的顺序执行
  • # 2.2.7. then必须返回一个promise [3.3]

    promise2 = promise1.then(onFulfilled, onRejected);

    • # 2.2.7.1. 如果onFulfilled或onRjected返回一个值x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
    • # 2.2.7.2. 如果onFulfilled或onRejected抛出一个异常e,promise2必须用e作为原因被拒绝
    • # 2.2.7.3. 如果onFulfilled不是一个函数并且promise1被解决,promise2必须用与promise1相同的值被解决
    • # 2.2.7.4. 如果onRejected不是一个函数并且promise1被拒绝,promise2必须用与promise1相同的原因被拒绝

# 2.3. Promise解决程序 (The Promise Resolution Procedure)

promise解决程序(promise resolution procedure)是一个抽象操作,它以一个promise和一个值作为输入,我们将其表示为[[Resolve]](promise, x)。如果x是一个thenable,它尝试让promise采用x的状态,并假设x的行为至少在某种程度上类似于promise。否则,它将会用值x解决 promise。

这种thenable的特性使得Promise的实现更具有通用性:只要其暴露一个遵循Promise/A+协议的then方法即可。这同时也使遵循Promise/A+规范的实现可以与那些不太规范但可用的实现能良好共存。

要运行[[Resolve]](promise, x),需要执行如下步骤:

  • # 2.3.1. 如果promise和x引用同一个对象,用一个TypeError作为原因来拒绝promise
  • # 2.3.2. 如果x是一个promise,采用它的状态:[3.4]
    • # 2.3.2.1. 如果x是等待态,promise必须保持等待状态,直到x被解决或拒绝
    • # 2.3.2.2. 如果x是解决态,用相同的值解决promise
    • # 2.3.2.3. 如果x是拒绝态,用相同的原因拒绝promise
  • # 2.3.3. 否则,如果x是一个对象或函数
    • # 2.3.3.1. 让then成为x.then。[3.5]
    • # 2.3.3.2. 如果检索属性x.then导致抛出了一个异常e,用e作为原因拒绝promise
    • # 2.3.3.3. 如果then是一个函数,用x作为this调用它。then方法的参数为俩个回调函数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise
      • 2.3.3.3.1. 如果resolvePromise用一个值y调用,运行[[Resolve]](promise, y)。译者注:这里再次调用[[Resolve]](promise,y),因为y可能还是promise
      • 2.3.3.3.2. 如果rejectPromise用一个原因r调用,用r拒绝promise。译者注:这里如果r为promise的话,依旧会直接reject,拒绝的原因就是promise。并不会等到promise被解决或拒绝
      • 2.3.3.3.3. 如果resolvePromise和rejectPromise都被调用,或者对同一个参数进行多次调用,那么第一次调用优先,以后的调用都会被忽略。译者注:这里主要针对thenable,promise的状态一旦更改就不会再改变。
      • 2.3.3.3.4. 如果调用then抛出了一个异常e,
        • 2.3.3.3.4.1. 如果resolvePromise或rejectPromise已经被调用,忽略它
        • 2.3.3.3.4.2. 否则,用e作为原因拒绝promise
    • # 2.3.3.4. 如果then不是一个函数,用x解决promise
  • # 2.3.4. 如果x不是一个对象或函数,用x解决promise

如果promise用一个循环的thenable链解决,由于[[Resolve]](promise, thenalbe)的递归特性,最终将导致[[Resolve]](promise, thenable)被再次调用,遵循上面的算法将会导致无限递归。规范中并没有强制要求处理这种情况,但也鼓励实现者检测这样的递归是否存在,并且用一个信息丰富的TypeError作为原因拒绝promise。[3.6]

# 3. 注解 Notes

  • # 3.1. 这里“平台代码”意味着引擎、环境以及promise的实现代码。在实践中,这需要确保onFulfilled和onRejected异步地执行,并且应该在then方法被调用的那一轮事件循环之后用新的执行栈执行。这可以用如setTimeout或setImmediate这样的“宏任务”机制实现,或者用如MutationObserver或process.nextTick这样的“微任务”机制实现。由于promise的实现被考虑为“平台代码”,因此在自身处理程序被调用时可能已经包含一个任务调度队列。

  • # 3.2. 严格模式下,它们中的this将会是undefined;在非严格模式,this将会是全局对象。

  • # 3.3. 假如实现满足所有需求,可以允许promise2 === promise1。每一个实现都应该记录是否能够产生promise2 === promise1以及什么情况下会出现promise2 === promise1。

  • # 3.4. 通常,只有x来自于当前实现,才知道它是一个真正的promise。这条规则允许那些特例实现采用符合已知要求的Promise的状态。

  • # 3.5. 这个程序首先存储x.then的引用,之后测试那个引用,然后再调用那个引用,这样避免了多次访问x.then属性。此类预防措施对于确保访问者属性的一致性非常重要,因为访问者属性的值可能在俩次检索之间发生变化。

  • # 3.6. 实现不应该在thenable链的深度上做任意限制,并且假设超过那个任意限制将会无限递归。只有真正的循环才应该引发一个TypeError;如果遇到一个无限循环的thenable,永远执行递归是正确的行为。

# 代码参考

代码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'


class Promise {
    constructor(executor) {
        // 2.1Promise必有个状态
        this._status = PENDING;
        // 1.3promise的值必须是合法的js值,
        this._value = undefined;
        // 1.5 表示promise的拒因
        this._reason = null;

        /**
         * 2.2.6. 同一个promise上的then可能被调用多次
         *   2.2.6.1. 如果promise被解决,所有相应的onFulfilled回调必须按照他们原始调用then的顺序执行
         *   2.2.6.2. 如果promise被拒绝,所有相应的onRejected回调必须按照他们原始调用then的顺序执行
         */
        this.onFulfilledCallback = [];
        this.onRejectedCallback = [];
        this.initBind();
        // 接受一个执行函数,并将resolve,和reject作为回调函数
        this.init(executor);
    }
    initBind() {
        // 绑定 this
        // 因为 resolve 和 reject 会在 exector 作用域中执行,因此这里需要将 this 绑定到当前的实例
        this.resolve = this.resolve.bind(this);
        this.reject = this.reject.bind(this);
    }

    init(executor) {
        try {
            executor(this.resolve, this.reject);
        } catch(err) {
            this.reject(err);
        }
    }
    resolve(value){
        /**
         * 2.1.1 当promise是等待(pending 状态 的时候 :
         *   2.1.1.1 可能变为解决或者拒绝状态。
         */
        if(this._status === PENDING) {
           setTimeout(() => {
            this._status = FULFILLED;
            this._value = value;
            // 2.2.2. 如果onFulfilled是一个函数
            // 2.2.2.1. 它必须在promise被解决后调用,promise的值作为它的第一个参数。
            this.onFulfilledCallback.forEach(cb => cb(value))   
           });
        }
    }
    reject(reason) {
        /**
         * 2.1.1 当promise是等待(pending 状态 的时候 :
         *   2.1.1.1 可能变为解决或者拒绝状态。
         */
        if(this._status === PENDING) {
            setTimeout(() => {
             this._status = REJECTED;
             this._reason = reason
             this.onRejectedCallback.forEach(cb => cb(reason))  
            });
        }
    }
    // 2.2 Promise必须提供一个then方法来访问当前或最终的值或原因。
    then(onFulfilled, onRejected) {
        /**
         * 2.2 Promise必须提供一个then方法来访问当前或最终的值或原因。
         */
        /**
         * 2.2.1 onFulfilled 和 onRejected 这俩参数都是可选的
         *   2.2.1.1 如果onFulfilled不是一个函数,它必须被忽略
         *   2.2.1.2. 如果onRejected不是一个函数,它必须被忽略
         * 2.2.5. onFulfilled和onRejected一定被作为函数调用(没有this值) [3.2]
         */
        onFulfilled = typeof(onFulfilled) === 'function' ? onFulfilled : value => value
        onRejected = typeof(onRejected) === 'function' ? onRejected : reason => { throw reason }

        let promise2
        // 2.2.4. 在执行上下文栈中只包含平台代码之前,onFulfilled或onRejected一定不能被调用 [3.1]
        if(this._status === PENDING) {
        // 2.2.7. then必须返回一个promise 
           return promise2 = new Promise((resolve,reject) => {
                this.onFulfilledCallback.push((value) => {
                    try {
                        const x = onFulfilled(value)
                        // 2.2.7.1. 如果onFulfilled或onRjected返回一个值x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                        Promise.resolvePromise(promise2,x,resolve,reject)
                    }catch(e) {
                        //2.2.7.2 如果onFulfilled或onRejected抛出一个异常e,promise2必须用e作为原因被拒绝
                        reject(e)
                    }
                })
                this.onRejectedCallback.push((reason) => {
                    try {
                        const x = onRejected(reason)
                        // 2.2.7.1. 如果onFulfilled或onRjected返回一个值x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
                        Promise.resolvePromise(promise2,x,resolve,reject)
                    }catch(e) {
                        //2.2.7.2 如果onFulfilled或onRejected抛出一个异常e,promise2必须用e作为原因被拒绝
                        reject(e)
                    }
                })
            })
        }
        
        if(this._status === FULFILLED) {
            return promise2 = new Promise((resolve,reject) =>{
                setTimeout(() => {
                    try{
                    // 2.2.6.1. 如果promise被解决,所有相应的onFulfilled回调必须按照他们原始调用then的顺序执行
                      const x = onFulfilled(this._value);
                      Promise.resolvePromise(promise2,x,resolve,reject);
                    }catch(e){
                      reject(e)
                    }
                })
            })
        }

        if(this._status === REJECTED) {
            return promise2 = new Promise((resolve,reject) => {
                setTimeout(() => {
                  try{
                    //   2.2.6.2. 如果promise被拒绝,所有相应的onRejected回调必须按照他们原始调用then的顺序执行
                    const x = onRejected(this._reason)
                    Promise.resolvePromise(promise2,x,resolve,reject)
                  }catch(e){
                    reject(e)
                  }
                });
            })
        }
    }
    catch(fn){
        return this.then(null,fn);
    }  
    
}

Promise.resolve = function(value) {
    return new Promise((resolve) => {
        resolve(value)
    })
}

Promise.reject = function(reason) {
    return new Promise((resolve,reject) => {
        reject(reason)
    })
}

Promise.deferred  = function() {
    const defer = {}
    defer.promise = new Promise((resolve, reject) => {
      defer.resolve = resolve
      defer.reject = reject
    })
    return defer
  }
  
Promise.resolvePromise = function(promise2,x,resolve,reject) {
    // 2.3.3.3.3. 如果resolvePromise和rejectPromise都被调用,或者对同一个参数进行多次调用,
    // 那么第一次调用优先,以后的调用都会被忽略。因为promise的状态一旦更改就不会再改变。
    // 所以定义一个变量,判断是否已被调用
    let called = false;

    // 2.3.1. 如果promise和x引用同一个对象,用一个TypeError作为原因来拒绝promise
    if(promise2 === x) {
        throw new TypeError("cannot return the same promise object from onfulfilled or on rejected callback.")
    }
    // 2.3.2. 如果x是一个promise,采用它的状态:[3.4]

    if(x instanceof Promise) {
        // 2.3.2.1. 如果x是等待态,promise必须保持等待状态,直到x被解决或拒绝
        if(x._status === PENDING) {
            x.then(y => {
                //  y 值,也有可能是新的 Promise,因此要递归的进行解析,
                /**
                 * new Promise1(resolve => {
                 *  resolve("Success")
                 * }).then(data => {
                 *  return new Promise1(resolve => {
                 *    resolve(new Promise1(resolve => {
                 *      resolve("Success3")
                 *    }))
                 *  })
                 * }).then(data => console.log(data))
                 */
                Promise.resolvePromise(promise2,y,resolve,reject)
            }, reason => {
                reject(reason)
            })
        } else {
            // #2.3.2.2. 如果x是解决态,用相同的值解决promise
            // #2.3.2.3. 如果x是拒绝态,用相同的原因拒绝promise
            x.then(resolve,reject)
        }
    } 
    // 2.3.3. 否则,如果x是一个对象或函数
    else if((x !== null && typeof x === "object") || typeof x === "function"){
        // 2.3.3.1. 让then成为x.then。[3.5]
        // 2.3.3.2. 如果检索属性x.then导致抛出了一个异常e,用e作为原因拒绝promise
        try {
            const then = x.then;
            // 2.3.3.3. 如果then是一个函数,用x作为this调用它。then方法的参数为俩个回调函数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise
            if(typeof then === 'function') {
                then.call(x, function resolvePromise(y) {
                    if(called) return;
                    called = true;
                    // 2.3.3.3.1. 如果resolvePromise用一个值y调用,运行[[Resolve]](promise, y)。译者注:这里再次调用[[Resolve]](promise,y),因为y可能还是promise
                    Promise.resolvePromise(promise2, y, resolve, reject)          
                }, function rejectPromise(r) {
                    if(called) return;
                    called = true;
                    // 2.3.3.3.2. 如果rejectPromise用一个原因r调用,用r拒绝promise。
                    reject(r)
                })
            } else {
                resolve(x)
            }
        }catch(e) {
            // 2.3.3.3.4. 如果调用then抛出了一个异常e,
            //      2.3.3.3.4.1. 如果resolvePromise或rejectPromise已经被调用,忽略它
            //      2.3.3.3.4.2. 否则,用e作为原因拒绝promise
            if(called) return;
            called = true;
            reject(e)
        }
    } else {
        resolve(x)
    }
}


Promise.race = function(promises) {
    return new Promise((resolve,reject) => {
        for(var i = 0; i < promises.length; i++) {
            promises[i].then(resolve,reject)
        }
    })
}
Promise.all = function (iterable) {
    let _resolve, _reject
    let remaining = iterable.length
    const results = []
    const promise = new Promise((resolve, reject) => {
        _resolve = resolve
        _reject = reject
    })
    iterable.forEach((p, i) => {
        Promise.resolve(p).then(res => {
            results[i] = res
            remaining --;
            if (remaining === 0) {
                _resolve(results);
            }
        }, _reject)
    });
    return promise;
};


Promise.all = function(arr) {
    return new Promise(function(resolve, reject) {
      if (!isArray(arr)) {
        return reject(new TypeError('Promise.all accepts an array'));
      }
      var args = Array.prototype.slice.call(arr);
      if (args.length === 0) return resolve([]);
      var remaining = args.length;
      function res(i, val) {
        try {
          if (val && (typeof val === 'object' || typeof val === 'function')) {
            var then = val.then;
            if (typeof then === 'function') {
              then.call(
                val,
                function(val) {
                  res(i, val);
                },
                reject
              );
              return;
            }
          }
          args[i] = val;
          if (--remaining === 0) {
            resolve(args);
          }
        } catch (ex) {
          reject(ex);
        }
      }
  
      for (var i = 0; i < args.length; i++) {
        res(i, args[i]);
      }
    });
  };

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

# 参考

  1. 这次彻底搞懂 Promise(手写源码多注释篇) (opens new window)
  2. Promise|async|Generator 实现&原理大解析 (opens new window)
  3. 阮一峰老师的Promise (opens new window)
  4. PromiseA+ 翻译 (opens new window)
  5. PromiseA+ 原文 (opens new window)
  6. 手写promise简易版 (opens new window)
  7. 手写Promise 二 (opens new window)
  8. 史上最最最详细的手写Promise教程 (opens new window)
  9. Promises (opens new window)
  10. Promise polyfill (opens new window)