Skip to content

Commit dec4e4a

Browse files
author
Forbes Lindesay
committed
re-write core.js
1 parent 99b8cfe commit dec4e4a

File tree

1 file changed

+92
-86
lines changed

1 file changed

+92
-86
lines changed

lib/core.js

Lines changed: 92 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,111 @@
11
'use strict';
22

3-
var asap = require('asap')
3+
var asap = require('asap/raw')
44

5-
// Use Symbol if it's available, but otherwise just
6-
// generate a random string as this is probably going
7-
// to be unique
8-
var handleSymbol = typeof Symbol === 'function' ?
9-
Symbol() :
10-
(
11-
'_promise_internal_key_handle_' +
12-
Math.random().toString(35).substr(2, 10) + '_'
13-
)
5+
function noop() {};
146

157
module.exports = Promise;
168
function Promise(fn) {
179
if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new')
1810
if (typeof fn !== 'function') throw new TypeError('not a function')
19-
var state = null
20-
var value = null
21-
var deferreds = []
22-
var self = this
23-
24-
this.then = function(onFulfilled, onRejected) {
25-
return new self.constructor(function(resolve, reject) {
26-
handle(new Handler(onFulfilled, onRejected, resolve, reject))
27-
})
11+
this._state = 0;
12+
this._value = null;
13+
this._deferreds = [];
14+
if (fn === noop) return;
15+
doResolve(fn, this);
16+
}
17+
Promise.prototype._safeThen = function (onFulfilled, onRejected) {
18+
var self = this;
19+
return new this.constructor(function (resolve, reject) {
20+
var res = new Promise(noop);
21+
res.then(resolve, reject);
22+
self._handle(new Handler(onFulfilled, onRejected, res));
23+
});
24+
};
25+
Promise.prototype.then = function(onFulfilled, onRejected) {
26+
if (this.constructor !== Promise) return this._safeThen(onFulfilled, onRejected);
27+
var res = new Promise(noop);
28+
this._handle(new Handler(onFulfilled, onRejected, res));
29+
return res;
30+
};
31+
Promise.prototype._handle = function(deferred) {
32+
if (this._state === 3) {
33+
this._value._handle(deferred);
34+
return;
2835
}
29-
this.then[handleSymbol] = handle;
30-
function handle(deferred) {
31-
return internalHandle(deferred);
36+
if (this._state === 0) {
37+
this._deferreds.push(deferred);
38+
return;
3239
}
33-
function internalHandle(deferred) {
34-
if (state === null) {
35-
deferreds.push(deferred)
40+
var state = this._state;
41+
var value = this._value;
42+
asap(function() {
43+
var cb = state === 1 ? deferred.onFulfilled : deferred.onRejected
44+
if (cb === null) {
45+
(state === 1 ? deferred.resolve(value) : deferred.reject(value))
3646
return
3747
}
38-
asap(function() {
39-
var cb = state ? deferred.onFulfilled : deferred.onRejected
40-
if (cb === null) {
41-
(state ? deferred.resolve : deferred.reject)(value)
42-
return
43-
}
44-
var ret
45-
try {
46-
ret = cb(value)
48+
var ret
49+
try {
50+
ret = cb(value)
51+
}
52+
catch (e) {
53+
deferred.reject(e)
54+
return
55+
}
56+
deferred.resolve(ret)
57+
});
58+
};
59+
Promise.prototype._resolve = function(newValue) {
60+
try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
61+
if (newValue === this) throw new TypeError('A promise cannot be resolved with itself.')
62+
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
63+
if (
64+
newValue instanceof Promise &&
65+
newValue._handle === this._handle &&
66+
newValue.then === this.then
67+
) {
68+
this._state = 3;
69+
this._value = newValue;
70+
for (var i = 0; i < this._deferreds.length; i++) {
71+
newValue._handle(this._deferreds[i]);
72+
}
73+
return;
4774
}
48-
catch (e) {
49-
deferred.reject(e)
75+
var then = newValue.then
76+
if (typeof then === 'function') {
77+
doResolve(then.bind(newValue), this)
5078
return
5179
}
52-
deferred.resolve(ret)
53-
})
54-
}
55-
56-
function resolve(newValue) {
57-
try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
58-
if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.')
59-
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
60-
var then = newValue.then
61-
if (typeof then === 'function') {
62-
if (typeof then[handleSymbol] === 'function') {
63-
// to prevent a memory leak, we adopt the value of the other promise
64-
// allowing this promise to be garbage collected as soon as nobody
65-
// has a reference to it
66-
internalHandle = then[handleSymbol];
67-
deferreds.forEach(function (deferred) {
68-
internalHandle(deferred);
69-
});
70-
} else {
71-
doResolve(then.bind(newValue), resolve, reject)
72-
}
73-
return
74-
}
75-
}
76-
state = true
77-
value = newValue
78-
finale()
79-
} catch (e) { reject(e) }
80-
}
81-
82-
function reject(newValue) {
83-
state = false
84-
value = newValue
85-
finale()
86-
}
87-
88-
function finale() {
89-
for (var i = 0, len = deferreds.length; i < len; i++)
90-
handle(deferreds[i])
91-
deferreds = null
92-
}
80+
}
81+
this._state = 1
82+
this._value = newValue
83+
this._finale()
84+
} catch (e) { this._reject(e) }
85+
}
9386

94-
doResolve(fn, resolve, reject)
87+
Promise.prototype._reject = function (newValue) {
88+
this._state = 2
89+
this._value = newValue
90+
this._finale()
91+
}
92+
Promise.prototype._finale = function () {
93+
for (var i = 0; i < this._deferreds.length; i++)
94+
this._handle(this._deferreds[i])
95+
this._deferreds = null
9596
}
9697

9798

98-
function Handler(onFulfilled, onRejected, resolve, reject){
99+
function Handler(onFulfilled, onRejected, promise){
99100
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
100101
this.onRejected = typeof onRejected === 'function' ? onRejected : null
101-
this.resolve = resolve
102-
this.reject = reject
102+
this.promise = promise;
103+
}
104+
Handler.prototype.resolve = function (value) {
105+
this.promise._resolve(value);
106+
};
107+
Handler.prototype.reject = function (value) {
108+
this.promise._reject(value);
103109
}
104110

105111
/**
@@ -108,21 +114,21 @@ function Handler(onFulfilled, onRejected, resolve, reject){
108114
*
109115
* Makes no guarantees about asynchrony.
110116
*/
111-
function doResolve(fn, onFulfilled, onRejected) {
117+
function doResolve(fn, promise) {
112118
var done = false;
113119
try {
114120
fn(function (value) {
115121
if (done) return
116122
done = true
117-
onFulfilled(value)
123+
promise._resolve(value)
118124
}, function (reason) {
119125
if (done) return
120126
done = true
121-
onRejected(reason)
127+
promise._reject(reason)
122128
})
123129
} catch (ex) {
124130
if (done) return
125131
done = true
126-
onRejected(ex)
132+
promise._reject(ex)
127133
}
128-
}
134+
}

0 commit comments

Comments
 (0)