手写Promise
const PENDING = 'pending';
const FULFIILED = 'fulfilled';
const REJECTED = 'rejected';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = value => {
if(this.status === PENDING) {
this.status = FULFIILED;
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
const reject = reason => {
if(this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v=> v;
onRejected = typeof onRejected === 'function'? onRejected : e => {throw e}
let promise2 = new Promise((resolve,reject) => {
if(this.status === FULFIILED) {
setTimeout(() => {
try{
let x = onFulfilled(this.value);
resolvePromise(x,promise2, resolve, reject);
}catch(e) {
reject(e)
}
}, 0);
}
if(this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x,promise2, resolve, reject);
}catch(e) {
reject(e);
}
}, 0);
}
if(this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onFulfilled(this.value);
resolvePromise(x,promise2, resolve, reject);
}catch(e) {
reject(e)
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x,promise2, resolve, reject);
}catch(e) {
reject(e);
}
}, 0);
})
}
});
return promise2;
}
}
function resolvePromise(x, promise2, resolve, reject) {
if(x === promise2) {
return reject(new TypeError("循环引用"))
}
if((typeof x === 'object' && x !== null) || typeof x === 'function') {
let called = false;
try{
let then = x.then;
if(typeof then === 'function') {
then.call(x, (y) => {
if(called) return;
called = true;
resolvePromise(y, promise2, resolve, reject)
}, (r) => {
if(called) return;
called = true;
reject(r)
});
}else{
resolve(x);
}
}catch(e) {
if(called) return;
called = true;
reject(e);
}
}else{
resolve(x);
}
}