/*
Custom promise
1. Perform MyPromise constructor to be executed immediately executor
2. promise instance of an object, the internal state of the three
Initialization pending
Successfully resolved
Failed rejected
Note: The status can only be modified once
If the internal executor wrong, promise to change the status rejected
3. then implement methods
promise.then(onResolved, onRejected)
promise of status is resolved, asynchronous function call onResolved
promise of status is rejected, asynchronous function call onRejected
promise of state is pending, the function is not called.
Future promise may change, at this time or asynchronously call the appropriate function
4. promise.then().then()
then method returns a value promise, chained to call
Returns status value promise object:
1. If no internal return value / return value is not a promise that is resolved
2. If the internal state of the return value is the promise of promise see
3. If the internal throw an exception, is rejected
*/
function MyPromise(executor) {
// Initialize the promise instance object state
this._status = 'pending';
// initialize result value promise instance object
this._value = undefined;
// initialize the storage container callback function
this._callbacks = {};
// cache this -> promise instance of an object
const _that = this;
try {
// error code may be placed
// Once inside the code wrong try, try running it will break the code, directly to the catch
// Perform MyPromise constructor to be executed immediately executor
executor(resolve, reject);
} catch (e) {
// to catch, description of the internal function executor wrong ~
// The promise object status change rejected
reject(e);
}
// Define resolve
function resolve(value) {
// status can only be modified once
if (_that._status === 'pending') {
// call the method will resolve objects promise to change the state status resolved
_that._status = 'resolved';
_that._value = value;
// function asynchronous call onResolved
if (_that._callbacks.onResolved) {
setTimeout(() => {
_that._callbacks.onResolved(value)
})
}
}
}
// define reject
function reject(reason) {
if (_that._status === 'pending') {
// Call reject method will promise to change the object state rejected state
_that._status = 'rejected';
_that._value = reason;
// function asynchronous call onRejected
if (_that._callbacks.onRejected) {
setTimeout(() => {
_that._callbacks.onRejected(reason)
})
}
}
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
const _that = this;
// If onResolved exist, unchanged
// If onResolved does not exist, explained catch trigger. If it is successful state promise, guarantee a successful return value or state promise
onResolved = onResolved ? onResolved : (value) => value;
// then pass a parameter only once method, and a failure state promise, guarantee that the returned value is the value of the internal state of the failed promise
onRejected = onRejected ? onRejected : (reason) => {
throw reason
};
// promise as a target for future use
let promise = null;
// this point to promise instance of an object
if (this._status === 'resolved') {
// Description promise object status is resolved
// function asynchronous call onResolved
promise = new MyPromise(function (resolve, reject) {
setTimeout(() => {
doResolve(onResolved, _that._value, resolve, reject);
})
})
} else if (this._status === 'rejected') {
promise = new MyPromise(function (resolve, reject) {
setTimeout(() => {
doResolve(onRejected, _that._value, resolve, reject);
})
})
} else {
// Description promise object's state is pending state
// callback function exists on this
promise = new MyPromise(function (resolve, reject) {
// _that is p1, p2 is outside promise
When // p1 call onResolved / onRejected callback to update status of p2
_that._callbacks.onResolved = function (value) {
doResolve(onResolved, value, resolve, reject);
};
_that._callbacks.onRejected = function (reason) {
doResolve(onRejected, reason, resolve, reject);
};
})
}
// To call chain
return promise;
}
// defined function code reuse
function doResolve(onFn, value, resolve, reject) {
try {
const result = onFn(value);
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
MyPromise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
}
MyPromise.prototype.finally = function (onResolved) {
const _that = this;
return new Promise((resolve, reject) => {
if (_that._status === 'pending') {
const callback = function (value) {
doResolve(onResolved, value, resolve, reject)
};
_that._callbacks.onResolved = callback;
_that._callbacks.onRejected = callback;
} else {
doResolve(onResolved, _that._value, resolve, reject);
}
})
}
// return a successful state promise
MyPromise.resolve = function (value) {
return new MyPromise((resolve, reject) => {
resolve(value);
})
}
// returns a failed state promise
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
})
}
// accepts an array (promise of n objects placed in the array), only if all the objects are to promise success status, the method is the success return value promise
// As long as there is a failure, the method returns the value of the promise will fail
MyPromise.all = function (promises) {
// promises of length
const promiseLength = promises.length;
// define identification variables: the number of objects promise of success
let resolvedCount = 0;
// successful outcome value
const resolvedValues = [];
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promiseLength; i++) {
const promise = promises[i];
// look at the state of promise
promise.then((value) => {
resolvedCount++;
// will not mess with the push, the output order
// use the index, in order to ensure order ok
resolvedValues[i] = value;
if (resolvedCount === promiseLength) {
// explanation had been successful
resolve(resolvedValues);
}
}, reject)
}
})
}
const promise = new MyPromise((resolve, reject) => {
console.log ( 'executor function performs ~');
setTimeout(() => {
// resolve(111);
reject(222);
}, 2000)
})
promise
.then(() => {
console.log(111);
// When the method is not passed then the second callback.
// then the state of accepting the promise of the object is a failed state, the return value is a failed state
})
.catch((reason) => {
console.log(222, reason);
// return Promise.reject();
// throw new Error(111)
return 333;
})
.then((value) => {
console.log(333, value);
})
.catch(() => {
console.log(444);
})