简单实现Promise

前言

关于什么是Promise以及用法这里就不多说了,图片看上去一目了然,图片引用自MDN

有一次面试,被要求手写代码实现一个简单的Promise,虽然经常用,但是当时只能就着Promise/A+规范扯两句代码,就是没写出来,于是就试着写一下

分析

1、Promise有3种状态

  • pending: 初始状态,pending可以转化为fulfilled或者rejected状态,并且只能有一次转化,并且不可逆
  • fulfilled: 成功状态
  • rejected: 失败状态

2、初始化Promise接收一个函数为参数,该函数有两个函数作为参数,分别是resolve和reject

  • resolve将pending转化为fulfilled,在成功时调用,并将成功结果作为参数传递
  • reject将pending转化为rejected,在失败时调用,并将失败结果当参数传递
    1
    2
    3
    4
    5
    6
    7
    8
    var promise = new Promise (function (resolve,reject) {
    if (<!--成功的条件-->){
    resolve(value)
    }
    else {
    reject(error)
    }
    })

3、方法then和catch

  • then注册状态转化的回调函数,接收onFulfilled或者onRejected,并返回一个新的Promise,保证链式调用
  • catch相当于 return this.then(null, onRejected),Promise对象的错误具有冒泡性质,错误会不断的向后传递,直到 .catch() 捕获
  • 如果then和catch接收的不是函数,就会发生穿透

实现

代码抄袭

深入理解 Promise (中)
剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类
深入 Promise(一)——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
158
159
160
161
162
163
164
165
166
167
168
;(function () {
var states = {
PENDING: 'pending',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}

function noop() {
}

function isFunction(func) {
return typeof func === 'function'
}

function CallbackItem(promise, onResolved, onRejected) {
this.promise = promise;
// 为了保证在promise链中,resolve或reject的结果可以一直向后传递,可以默认给then添加resolvedFn和rejectedFn
// 穿透
this.onResolved = isFunction(onResolved) ? onResolved : function (v) {
return v
}
this.onRejected = isFunction(onRejected) ? onRejected : function (r) {
throw r
}
}

CallbackItem.prototype.resolve = function (value) {
executeCallbackAsync.bind(this.promise)(this.onResolved, value);
}
CallbackItem.prototype.reject = function (value) {
executeCallbackAsync.bind(this.promise)(this.onRejected, value);
}

function getThen(obj) {
console.log(obj)
var then = obj && obj.then;
if (obj && typeof obj === 'object' && isFunction(then)) {
return function appyThen() {
then.apply(obj, arguments);
};
}
}
// 抽象出执行resolve和reject的回调
function executeCallback(type, x) {
var isResolve = type === 'resolve',
thenable;

if (isResolve && (typeof x === 'object' || isFunction(x))) {
try {
thenable = getThen(x);
} catch (e) {
return executeCallback.bind(this)('reject', e);
}
}
if (isResolve && thenable) {
executeResolver.bind(this)(thenable);
} else {
this.state = isResolve ? states.FULFILLED : states.REJECTED;
this.data = x;
this.callbackQueue.forEach(v => v[type](x));
}
return this;
}

// 用于执行 new Promise(function(resolve, reject){}) 中的resove或reject方法
function executeResolver(resolver) {
//[标准 2.3.3.3.3] 如果resove()方法多次调用,只响应第一次,后面的忽略
var called = false,
_this = this;

function onError(y) {
if (called) {
return;
}
called = true;
//[标准 2.3.3.3.2] 如果是错误 使用reject方法
executeCallback.bind(_this)('reject', y);
}

function onSuccess(r) {
if (called) {
return;
}
called = true;
//[标准 2.3.3.3.1] 如果是成功 使用resolve方法
executeCallback.bind(_this)('resolve', r);
}
// 使用try...catch执行
//[标准 2.3.3.3.4] 如果调用resolve()或reject()时发生错误,则将状态改成rejected,并将错误reject出去
try {
resolver(onSuccess, onError);
} catch (e) {
onError(e);
}
}
// 用于异步执行 .then(onResolved, onRejected) 中注册的回调
function executeCallbackAsync(callback, value) {
var _this = this;
setTimeout(function () {
var res;
try {
res = callback(value);
} catch (e) {
return executeCallback.bind(_this)('reject', e);
}

if (res !== _this) {
return executeCallback.bind(_this)('resolve', res);
} else {
return executeCallback.bind(_this)('reject', new TypeError('Cannot resolve promise with itself'));
}
}, 4)
}

function Promise(resolver) {
// 初始化Promise
if (resolver && !isFunction(resolver)) {
throw new TypeError('resolver is not a function')
}
// 当前Promise的状态
this.state = states.PENDING
// 成功时的value或者失败时的reason,默认是undefined
this.data = void 0
// 保存注册的回调函数的队列
this.callbackQueue = []
// 抽象出executeResolver方法,包装resolve、reject
if (resolver) {
executeResolver.call(this, resolver)
}
}

Promise.prototype.then = function (onResolved, onRejected) {
//[标准 2.2.1 - 2.2.2] 状态已经发生改变并且参数不是函数时,则忽略
if (!isFunction(onResolved) && this.state === states.FULFILLED ||
!isFunction(onRejected) && this.state === states.REJECTED) {
return this
}
// 实例化一个新的Promise对象
var promise = new this.constructor()
// 一般情况下,状态发生改变时,走这里
if(this.state !== states.PENDING){
var callback = this.state === states.FULFILLED ? onResolved : onRejected
// 将上一步 resolve(value)或rejecte(value) 的 value 传递给then中注册的 callback
// [标准 2.2.4] 异步调用callback
executeCallbackAsync.bind(promise)(callback, this.data)
}else{
// var promise = new Promise(resolve=>resolve(1)); promise.then(...); promise.then(...); ...
// 一个实例执行多次then, 这种情况会走这里 [标准 2.2.6]
this.callbackQueue.push(new CallbackItem(promise, onResolved, onRejected))
}
// 返回新的实例 [标准 2.2.7]
return promise
}

Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected)
}

Promise.prototype.done = function(onResolved, onRejected){
this.then(onResolved, onRejected).catch(function (error) {
setTimeout(function () {
throw error
}, 0)
})
}

module.exports = Promise
})()

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var http = require('request');
var Promise = require('./promise-test')

var promise = new Promise(function(resolve, reject) {
http.post(yourUrl,function (error, response, body) {
if(error){
reject(error)
} else{
var res = JSON.parse(response.body)
resolve(res.re)
}
})
})
.then(function(cities){
console.log(cities[0])
})
.catch(function(error){
console.log(error)
})