class Promise {
callbacks = [];
name = '';
state = 'pending';
value = null;
constructor(fn) {
this.name = `Promse-${promiseCount++}`;
console.log('[%s]:constructor', this.name);
fn(this._resolve.bind(this), this._reject.bind(this));
}
then(onFulfilled, onRejected) {
console.log('[%s]:then', this.name);
return new Promise((resolve, reject) => {
this._handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
});
}
static resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise(resolve => {
then(resolve);
});
} else if (value) {
return new Promise(resolve => resolve(value));
} else {
return new Promise(resolve => resolve());
}
}
static reject(value) {
if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise((resolve, reject) => {
then(reject);
});
} else {
return new Promise((resolve, reject) => reject(value));
}
}
static all(promises) {
const l = promises.length
let i = 0
const resArr = new Array(promises.length)
return new Promise((resolve, reject) => {
promises.forEach((v, j) => {
Promise.resolve(v).then((res, rej) => {
i++
resArr[j] = res
if (l === i) resolve(resArr)
}, err => reject(err))
})
})
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise, index) => {
Promise.resolve(promise).then(result => {
resolve(result);
}, reason => reject(reason));
})
})
}
_handle(callback) {
console.log('[%s]:_handle', this.name, 'state=', this.state);
if (this.state === 'pending') {
this.callbacks.push(callback);
console.log('[%s]:_handle', this.name, 'callbacks=', this.callbacks);
return;
}
let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
if (!cb) {
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
cb(this.value);
return;
}
let ret
try {
ret = cb(this.value);
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
} catch (error) {
ret = error;
cb = callback.reject
} finally {
cb(ret);
}
}
_resolve(value) {
if (this.state !== 'pending') {
throw new Error('Promise state is single! ')
return
}
console.log('[%s]:_resolve', this.name);
console.log('[%s]:_resolve', this.name, 'value=', value);
if (value && (typeof value === 'object' || typeof value === 'function')) {
var then = value.then;
if (typeof then === 'function') {
then.call(value, this._resolve.bind(this), this._reject.bind(this));
return;
}
}
this.state = 'fulfilled';
this.value = value;
this.callbacks.forEach(callback => this._handle(callback));
}
_reject(error) {
if (this.state !== 'pending') {
throw new Error('Promise state is single! ')
return
}
console.log('[%s]:_reject', this.name);
console.log('[%s]:_reject', this.name, 'value=', error);
this.state = 'rejected';
this.value = error;
this.callbacks.forEach(callback => this._handle(callback));
}
}