# 9. 实现一个Promise/A+ 规范的Promise

# 1.简易版

class Promisex {
  constructor(fn) {
    this.state = 'pending';
    this.value = null;
    this.reason = null;

    this.FulfilledStack = [];
    this.RejectedStack = [];
    let resolve = (val)=>{
      setTimeout(() => {
        if (this.state == "pending") {
          this.value = val;
          this.state = 'fulfilled';
          let queue;
          while (queue = this.FulfilledStack.shift()) {
            queue(val)
          }
        }
      });
    }

    let reject = (val)=>{
      setTimeout(() => {
        if (this.state == "pending") {
          this.state = "rejected"
          this.reason = val;
          let queue;
          while (queue = this.RejectedStack.shift()) {
            queue(val)
          }
        }
      });
    }
    try {
      fn(resolve,reject);
    } catch (error) {
      reject(error)
    }
  }

  then(fulfilled,rejected) {
    if (typeof fulfilled == 'function') {
      this.FulfilledStack.push(fulfilled)
    }
    if (typeof rejected == 'function') {
      this.RejectedStack.push(rejected);
    }
    return this;
  }
   
  static all(list) {
    return new Promisex((resolve,reject)=>{
      let ans = [];
      let count = 0;
      for (let i = 0;i < list.length;i++) {
        this.resolve(list[i]).then(res=>{
          ans[i] = res;
          count++;
          if (count === list.length) {
            resolve(ans);
          }
        },e=>{
          reject(e);
        })
      }
    })
  }
  
  static race(list) {
    return new Promisex((resolve,reject)=>{
      for (let i = 0;i < list.length;i++) {
        this.resolve(list[i]).then(res=>{
          resolve(res);
        },e=>{
          reject(e);
        })
      }
    })
  }

  static resolve(v) {
    if (v instanceof Promisex) {
      return v;
    } else {
      return new Promisex(resolve=>{
        resolve(v)
      })
    }
  }
}
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

# 2.测试

new Promisex(function(resolve,reject) {
  setTimeout(() => {
    resolve(2);
  }, 2000);
}).then(res=>{
  console.log(res);
  return res;
}).then(res=>{
  console.log(3,res);
})


let a = new Promisex(function(resolve,reject) {
  setTimeout(() => {
    resolve(1);
  }, 2000);
})

let b = new Promisex(function(resolve,reject) {
  setTimeout(() => {
    resolve(2);
  }, 3000);
})

let c = new Promisex(function(resolve,reject) {
  setTimeout(() => {
    resolve(3);
  }, 1000);
})

Promisex.all([a,b,c]).then(res=>{
  console.log(res);
})
Promisex.race([a,b,c]).then(res=>{
  console.log(res);
})
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

# 3.完整版

// promise 三个状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED ='rejected';
class Promisex {
  constructor(fn){
    if(typeof fn !== 'function') throw new Error('Promisex must accept a function')
    this.state = PENDING;//初始状态
    this.value = null;//返回的信息/拒绝的原因

    this.onFulfilledQueues = [];//存储fulfilled状态对应onFulfilled函数队列
    this.onRejectedQueues = [];//存储rejected状态对应onRejected函数队列

    // value成功态时接收的终值
    const resolve=(value) => {
      if(value instanceof Promisex){
        return value.then(resolve,reject);
      }else{
        //加setTimeout原因:
        //实践中要确保 onFulfilled 和 onRejected 方法异步执行,
        setTimeout(() => {
          if(this.state!==PENDING) return;
          this.state = FULFILLED;
          this.value = value;
          let cb;
          while (cb = this.onFulfilledQueues.shift()) {
            cb(value)
          }
        });
      }
    }

    // reason失败态时接收的拒因
    const reject=(reason)=>{
      setTimeout(() => {
        if(this.state!==PENDING) return;
        this.state = REJECTED;
        this.value = reason;
        let cb;
        while (cb = this.onRejectedQueues.shift()) {
          cb(reason)
        }
      });
    }

    //执行
    try {
      fn(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }

  //注册fulfilled状态/rejected状态对应的回调函数
  //then返回一个新的promise对象
  //then中需要处理三种状态
  then(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };

    let newPromise;
    if(this.state===FULFILLED){//成功状态
      return newPromise=new Promisex((resolve,reject)=>{
        setTimeout(() => {
          try {
            let x=onFulfilled(this.value);//onFulfilled有返回值
            resolvePromise(newPromise,x,resolve,reject);
          } catch (e) {
            reject(e)
          }
        });
      })
    }
    if(this.state===REJECTED){//失败状态
      return newPromise=new Promisex((resolve,reject)=>{
        setTimeout(() => {
          try {
            //不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected。
            let x=onRejected(this.value);//onRejected有返回值
            resolvePromise(newPromise,x,resolve,reject);
          } catch (e) {
            reject(e)
          }
        });
      })
    }
    if(this.state===PENDING){//等待状态
      //将onFulfilled/onRejected收集暂存到队列中
      return newPromise=new Promisex((resolve,reject)=>{
        this.onFulfilledQueues.push((value)=>{
          try {
            let x=onFulfilled(value);
            resolvePromise(newPromise,x,resolve,reject);
          } catch (e) {
            reject(e)
          }
        })
        this.onRejectedQueues.push((reason)=>{
          try {
            let x=onRejected(reason);
            resolvePromise(newPromise,x,resolve,reject);
          } catch (e) {
            reject(e);
          }
        })
      })
    }
  }

  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(cb){
    return this.then(value=>{
      Promisex.resolve(cb()).then(()=>value)
    },err=>{
      Promisex.resolve(cb()).then(()=>{throw err})
    })
  }

  static resolve(value){
    if(value instanceof Promisex) return value;
    return new Promisex(resolve=>resolve(value));
  }

  static reject(reason){
    return new Promisex((undefined,reject)=>reject(reason));
  }

  static all(list){
    return new Promisex((resolve,reject)=>{
      let values=[];
      let count=0;
      for(let [i,p] of list.entries()){
        this.resolve(p).then(res=>{
          values[i]=res;
          count++;
          if(count === list.length) resolve(values);
        },err=>{
          reject(err);
        })
      }
    })
  }

  static race(list){
    return new Promisex((resolve,reject)=>{
      for(let p of list){
        this.resolve(p).then(res=>{
          resolve(res);
        },err=>{
          reject(err);
        })
      }
    })
  }
}


function resolvePromise(promise2,x,resolve,reject){
  if(promise2===x){// 如果从onFulfilled中返回的x 就是promise2 就会导致循环引用报错
    return reject(new TypeError('循环引用'))
  }

  let called = false;// 避免多次调用
  // * 1.promise对象
  // * 2.thenable对象/函数
  // * 3.普通值
  if(x instanceof Promisex){
    if(x.state===PENDING){
      x.then(y=>{
        resolvePromise(promise2,y,resolve,reject);
      },reason=>{
        reject(reason)
      })
    }else{
      x.then(resolve,reject);
    }
  }else if(x&&(typeof x==='object'||typeof x==='function')){
    try {
      //是否是thenable对象(具有then方法的对象/函数)
      let then = x.then;
      if(typeof then==='function'){
        then.call(x,y=>{
          if(called)return;
          called=true;
          resolvePromise(promise2,y,resolve,reject);
        },reason=>{
          if(called)return;
          called=true;
          reject(reason);
        })
      }else{//说明是一个普通对象
        resolve(x)
      }
    } catch (e) {
      if(called)return;
      called=true;
      reject(e)
    }
  }else{
    resolve(x);
  }
}

//使用promises-aplus-tests测试
Promisex.deferred = function() {
  // 延迟对象
  let defer = {};
  defer.promise = new Promisex((resolve, reject) => {
    defer.resolve = resolve;
    defer.reject = reject;
  });
  return defer;
};
module.exports = Promisex;
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

最后执行promises-aplus-tests ./xxx.js进行测试

# 4.例子

//不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected。
new Promisex((resolve, reject)=>{
  setTimeout(() => {
    reject(2)
  }, 2000);
}).then(res=>{
  console.log(res);
  return res+1;
},e=>{
  return e;//2
}).then(res=>{
  console.log(res)//2
},e=>{
  return e;
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 5.参考

Promise详解与实现(Promise/A+规范) (opens new window)

Promises/A+规范(英文) (opens new window)

【翻译】Promises/A+规范 (opens new window)

Javascript异步编程的4种方法 (opens new window)