-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuPromise.js
172 lines (157 loc) · 4.01 KB
/
uPromise.js
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
/**
* Promise的三种状态
* @type {Number}
*/
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
var noop = function () {};
/**
* Promise类
* @param {Function} resolver
*/
function uPromise(resolver) {
console.log(resolver);
if (!_.isFunction(resolver)) {
throw new TypeError(' Promise resolver undefined is not a function!')
}
this.state = PENDING; // 当前promise状态
this.value = void 0; // state为FULFILLED时存储返回值 为REJECTED时返回错误值
this.queue = []; // 回调队列
if (resolver !== noop) {
runResolverSafely(this, resolver)
} else {
return;
}
}
/**
* 安全执行resolver函数
* @param {Object} ctx 上下文执行环境,Promise实例
* @param {Function} then resolver
* @return {Object} Promise实例
*/
function runResolverSafely(ctx, then) {
// 控制执行一次
var called = false;
try {
then(function (value) {
if (called) {
return;
}
called = true;
runResolve(ctx, value);
}, function (error) {
if (called) {
return;
}
called = true;
runReject(ctx, error);
});
} catch (error) {
if (called) {
return;
}
called = true;
runReject(ctx, error);
}
}
/**
* 执行resolver函数里的resolve函数参数
* @param {Object} ctx Promise实例的上下文执行环境
* @param {Any} value resolve函数的参数
* @return {Promise} 此次Promise实例
*/
function runResolve(ctx, value) {
try {
var then = getThen(value);
if (then) {
runResolve(ctx, then);
} else {
ctx.state = FULFILLED;
ctx.value = value;
ctx.queue.map(function (item) {
item.callFulfilled(value);
});
}
return ctx;
} catch (e) {
return runReject(value);
}
}
/**
* 执行resolver函数里的reject函数参数
* @param {Object} ctx Promise实例的上下文执行环境
* @param {Error} error 错误对象
* @return {Promise} 此次Promise实例
*/
function runReject(ctx, error) {
ctx.state = REJECTED;
ctx.value = error;
ctx.queue.map(function (item) {
item.callRejected(error);
});
return ctx;
}
/**
* 获取then
* @param {Object} obj
* @return {Function}
*/
function getThen(obj) {
var then = obj && obj.then;
if (obj && (_.isObject(obj) || _.isFunction(obj)) && _.isFunction(then)) {
return function appyThen() {
then.apply(obj, arguments);
};
}
}
uPromise.prototype.then = function (onFulfilled, onRejected) {
if (_.isFunction(onFulfilled) && this.state === FULFILLED || _.isFunction(onRejected) && this.state === REJECTED) {
return this;
}
var promise = new this.constructor(noop);
if (this.state !== PENDING) {
var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
unwrap(promise, resolver, this.value);
} else {
this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
}
return promise;
};
uPromise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
};
function QueueItem(promise, onFulfilled, onRejected) {
this.promise = promise;
this.callFulfilled = function (value) {
runResolve(this.promise, value);
};
this.callRejected = function (error) {
runReject(this.promise, error);
};
if (_.isFunction(onFulfilled)) {
this.callFulfilled = function (value) {
unwrap(this.promise, onFulfilled, value);
};
}
if (_.isFunction(onRejected)) {
this.callRejected = function (error) {
unwrap(this.promise, error);
};
}
}
function unwrap(promise, func, value) {
_.defer(function () {
var returnValue;
try {
returnValue = func(value);
} catch (error) {
return runReject(promise, error);
}
if (returnValue === promise) {
runReject(promise, new Error('Cannot resolve promise with itself'));
} else {
runResolve(promise, returnValue);
}
});
}