const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const isFn = fn => typeof fn === 'function';
class Promise {
constructor(resolver) {
if (!isFn(resolver)) {
throw new TypeError('Promise 引數必須是函式');
}
this._status = PENDING;
this._value;
this._fulfilledQueue = [];
this._rejectedQueue = [];
this._resolve = this._resolve.bind(this);
this._reject = this._reject.bind(this);
resolver(this._resolve, this._reject);
}
_resolve(val) {
if (this._status !== PENDING) return;
setTimeout(() => {
this._status = FULFILLED;
this._value = val;
let cb;
while (cb = this._fulfilledQueue.shift()) {
cb(this._value)
}
}, 0);
}
_reject(val) {
if (this._status !== PENDING) return;
setTimeout(() => {
this._status = REJECTED;
this._value = val;
let cb;
while (cb = this._rejectedQueue.shift()) {
cb(this._value)
}
}, 0);
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
let runThen = (callback, resolver) => {
return function (val) {
try {
if (!isFn(callback)) {
resolver(val)
} else {
const res = callback(val);
if (res instanceof Promise) {
res.then(resolve, reject);
} else {
resolver(res)
}
}
} catch (err) {
reject(err);
}
}
}
switch (this._status) {
case FULFILLED:
runThen(onFulfilled, resolve)(this._value);
break;
case REJECTED:
runThen(onRejected, reject)(this._value);
break;
case PENDING:
this._fulfilledQueue.push(runThen(onFulfilled, resolve));
this._rejectedQueue.push(runThen(onRejected, reject));
break;
}
});
}
static resolve(promise) {
if (promise instanceof Promise) {
return promise;
} else {
return new Promise(resolve => {
resolve(promise);
});
}
}
static reject(err){
return new Promise((resolve, reject) => reject(err));
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(callback) {
return this.then(
value => Promise.resolve(callback()).then(() => value),
reason => Promise.resolve(callback()).then(() => { throw reason })
);
}
static race(pmList) {
return new Promise((resolve, reject) => {
pmList.forEach(item => {
Promise.resolve(item).then(val => {
resolve(val);
}, err => {
reject(err);
});
})
})
}
static all(pmList) {
return new Promise((resolve, reject) => {
let resolveArr = [];
let count = 0;
pmList.forEach((item, index) => {
Promise.resolve(item).then(val => {
resolveArr[index] = val;
count++;
if (count === pmList.length) {
resolve(resolveArr);
}
}, err => {
reject(err);
});
})
})
}
}
複製程式碼