Handwritten Promise ideas
First step by step analysis, step by step to write code, and finally have a complete example
1. Promise is a class whose argument is a function executor that executes immediately. The function executor takes two arguments, a success callback resolve and a failure callback reject
class MyPromise {
constructor(executor) {
executor(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {}
reject(reason){}}Copy the code
Three pending in the state, 2. Promise fulfilled, rejected, and the initial state is pending, when the promise of change once the state is unable to change
// Define constant values externally
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending'; .constructor(executor) {
// Sets the current promise state value
this.status = PENDING;
executor(this.resolve.bind(this), this.reject.bind(this)); }...Copy the code
3. The resolve/reject method changes the state of the current PROMISE
.resolve(value) {
// If the current state is not the initial state, it cannot be modified
if (this.status ! == PENDING)return;
// Change the current status to succeeded
this.status = FULFILLED; }...reject(reason) {
// If the current state is not the initial state, it cannot be modified
if (this.status ! == PENDING)return;
// Change the current status to failed
this.status = REJECTED;
}
Copy the code
4. Promise has a then method that takes two arguments, the first being the promise’s successful callback and the second a failed callback
/* Because successCallback and failCallback accept arguments in resolve and Reject, success and failure values */ are logged.constructor(executor){...// Records the value returned on success
this.value = undefined;
// Records the value returned on failure
this.reason = undefined; . }...resolve(value){...// Records the value returned on success
this.value = value; }...reject(reason){...// Records the value returned on failure
this.reason = reason; }...then(successCallback, failCallback) {
if (this.status === FULFILLED) {
successCallback(this.value)
} else if (this.status === REJECTED) {
failCallback(this.reason)
}
}
......
Copy the code
5. When the function executor is synchronous, the state of the promise changes immediately, so then can receive the state processing success and failure, but when the function executor is asynchronous, the state of the promise is waiting state, and the success and failure callback needs to be recorded. Call the corresponding callback function after the asynchronous executor completes execution
/* So we need two variables to store success and failure callbacks for the then method. When the asynchronous executor completes, resolve/reject executes success and failure callbacks for the then method, respectively.constructor(executor){...// Record a successful callback
this.successCallback = undefined;
// Record the failed callback
this.failCallback = undefined; . }...then(successCallback, failCallback){...else if (this.status === PENDING) {
this.successCallback = successCallback;
this.failCallback = failCallback; }}...resolve(value){...// If the actuator is asynchronous, the execution of the actuator is complete, and the callback must be executed successfully
this.successCallback(this.value); }...reject(reason){...// If the actuator is asynchronous, the actuator completes and a failure callback needs to be executed
this.failCallback(this.reason); }...Copy the code
6. A promise can also perform multiple then method, and the callback will perform, then method when the function actuators for synchronous, we don’t need to do to deal with, but when the function of actuators is asynchronous, we need to keep every callback function then method, when the function of the actuator has been completed, So, storing success and failure callbacks is an array
// The variables storing successful and failed callbacks are arrays.constructor(executor){...// Record a successful callback
this.successCallback = [];
// Record the failed callback
this.failCallback = []; . }...then(successCallback, failCallback){...else if (this.status === PENDING) {
this.successCallback.push(successCallback);
this.failCallback.push(failCallback); }}...resolve(value){...// If the actuator is asynchronous, the execution of the actuator is complete, and the callback must be executed successfully
while (this.successCallback.length)this.successCallback.shift()(this.value); }...reject(reason){...// If the actuator is asynchronous, the actuator completes and a failure callback needs to be executed
while (this.failCallback.length) this.failCallback.shift()(this.reason); }...Copy the code
7. A promise can be chained to a then method, meaning that the then method must return a promise. The second THEN is a call to the promise object returned in the first THEN, so that the API can continuously pass parameters without going back to hell. If a normal value is returned in a successful callback in the first THEN, the next THEN will receive the value, or if it is a PROMISE, the next THEN will wait for the promise to complete and then pass the value on
then(successCallback, failCallback) {
/ * to determine whether the return value of a current successCallback/failCallback asynchronous, if asynchronous need to wait until the asynchronous completion * /
const resolvePromise = (x, resolve, reject) = > {
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else{ resolve(x); }}const promise2 = new MyPromise((resolve, reject) = > {
if (this.status === FULFILLED) {
const x = successCallback(this.value)
resolvePromise(x, resolve, reject);
} else if (this.status === REJECTED) {
const x = failCallback(this.reason);
resolvePromise(x, resolve, reject)
} else if (this.status === PENDING) {
this.successCallback.push(() = > {
const x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject)
});
this.failCallback.push(() = > {
const x = failCallback(this.reason) resolvePromise(promise2, x, resolve, reject) }); }})returnpromise2; }...// There is no need to pass this.value/this.reason
resolve(value){...// If the actuator is asynchronous, the execution of the actuator is complete, and the callback must be executed successfully
while (this.successCallback.length) this.successCallback.shift()(); }...reject(reason){...// If the actuator is asynchronous, the actuator completes and a failure callback needs to be executed
while (this.failCallback.length) this.failCallback.shift()(); }...Copy the code
8. You cannot return your promose object in the then method, otherwise a circular call will occur
/* If x is the same as promise2, use a timer to change the callback to an asynchronous */
then(successCallback, failCallback) {
/ * to determine whether the return value of a current successCallback/failCallback asynchronous, if asynchronous You may need to wait until the asynchronous completion * /
const resolvePromise = (promise, x, resolve, reject) = > {
if (promise === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (x instanceof MyPromise) {
x.then(resolve, reject);
} else{ resolve(x); }}const promise2 = new MyPromise((resolve, reject) = > {
if (this.status === FULFILLED) {
setTimeout(() = > {
const x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject);
}, 0)}else if (this.status === REJECTED) {
setTimeout(() = > {
const x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject)
}, 0)}else if (this.status === PENDING) {
this.successCallback.push(() = > {
setTimeout(() = > {
const x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject)
}, 0)});this.failCallback.push(() = > {
setTimeout(() = > {
const x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
}, 0)}); }})return promise2;
}
Copy the code
9. Error handling: Reject callback is executed when the function executor fails, reject callback is executed when the THEN method fails, reject callback is executed when the THEN method fails, reject callback is executed when the THEN method fails, reject callback is executed when the THEN method fails, reject callback is executed when the THEN method fails, reject callback is executed
// First grab the actuator error
constructor(executor){...The executor, which executes immediately, takes two arguments, a successful callback and a failed callback
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
// Grab errors in then
then(successCallback, failCallback) {
/ * to determine whether the return value of a current successCallback/failCallback asynchronous, if asynchronous You may need to wait until the asynchronous completion * /
const resolvePromise = (promise, x, resolve, reject) = > {
if (promise === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (x instanceof MyPromise) {
x.then(resolve, reject);
} else{ resolve(x); }}const promise2 = new MyPromise((resolve, reject) = > {
if (this.status === FULFILLED) {
setTimeout(() = > {
try {
const x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0)}else if (this.status === REJECTED) {
setTimeout(() = > {
try {
const x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)}else if (this.status === PENDING) {
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)});this.failCallback.push(() = > {
setTimeout(() = > {
try {
const x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)}); }})return promise2;
}
Copy the code
Resolve (resolve, resolve); resolve (resolve, resolve); resolve (resolve, resolve)
then(successCallback, failCallback) {
// Arguments become optional, passing similar functions when no arguments are passed
// If it is a normal value, ignore it
if (successCallback) {
if (typeofsuccessCallback ! = ='function') {
successCallback = value= >value; }}else {
successCallback = value= > value;
}
if (failCallback) {
if (typeoffailCallback ! = ='function') {
reason= > { throw reason }
}
} else {
reason= > { throw reason }
}
......
}
Copy the code
Promise. All is a static method that can execute multiple promises, as well as normal values
static all(array) {
const result = [];
let i = 0;
return new MyPromise((resolve, reject) = > {
const addData = (key, value) = > {
result[key] = value;
i++;
if (i === array.length) {
resolve(result);
}
}
array.forEach((item, index) = > {
if (item instanceof MyPromise) {
item.then(value= > addData(index, value), error= > reject(error))
} else{ addData(index, item); }})})}Copy the code
Resolve is a static method that passes a single argument, and returns a promise if it is a normal argument, or a promise if it is a promise
static resolve(item) {
if (item instanceof MyPromise) {
return item;
} else {
return new MyPromise(resolve= > {
resolve(item)
})
}
}
Copy the code
The promise.reject method passes an argument, returns a promise, and passes the argument down into the second callback of the then method
static reject(error) {
return new MyPromise((resolve, reject) = > {
reject(error)
})
}
Copy the code
If a finally method returns a promise, then must wait. If a finally method returns a promise, then must wait. If a finally method returns a promise, then must wait
finally(callback) {
return this.then(value= > {
const x = callback();
return MyPromise.resolve(x).then(() = > value)
}, error= > {
const x = callback();
return MyPromise.reject(x).then(undefined.() = > error)
})
}
Copy the code
15. The catch method is equivalent to executing a failed callback in then
catch(callback) {
this.then(undefined, callback);
}
Copy the code
Promise complete example
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';
/* Bind this declaratively */; /* bind this declaratively */
class MyPromise {
constructor(executor) {
// Sets the current promise state value
this.status = PENDING;
// Records the value returned on success
this.value = undefined;
// Records the value returned on failure
this.reason = undefined;
// Record a successful callback
this.successCallback = [];
// Record the failed callback
this.failCallback = [];
The executor, which executes immediately, takes two arguments, a successful callback and a failed callback
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
resolve(value) {
// If the current state is not the initial state, it cannot be modified
if (this.status ! == PENDING)return;
// Change the current status to succeeded
this.status = FULFILLED;
// Records the value returned on success
this.value = value;
// If the actuator is asynchronous, the execution of the actuator is complete, and the callback must be executed successfully
while (this.successCallback.length) this.successCallback.shift()();
}
reject(reason) {
// If the current state is not the initial state, it cannot be modified
if (this.status ! == PENDING)return;
// Change the current status to failed
this.status = REJECTED;
// Records the value returned on failure
this.reason = reason;
// If the actuator is asynchronous, the actuator completes and a failure callback needs to be executed
while (this.failCallback.length) this.failCallback.shift()();
}
then(successCallback, failCallback) {
// Arguments become optional, passing similar functions when no arguments are passed
// If it is a normal value, ignore it
if (successCallback) {
if (typeofsuccessCallback ! = ='function') {
successCallback = value= >value; }}else {
successCallback = value= > value;
}
if (failCallback) {
if (typeoffailCallback ! = ='function') {
reason= > { throw reason }
}
} else {
reason= > { throw reason }
}
const resolvePromise = (promise2, x, resolve, reject) = > {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (x instanceof MyPromise) {
x.then(resolve, reject);
} else{ resolve(x); }}const promise2 = new MyPromise((resolve, reject) = > {
if (this.status === FULFILLED) {
setTimeout(() = > {
try {
const x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)}else if (this.status === REJECTED) {
setTimeout(() = > {
try {
const x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)}else if (this.status === PENDING) {
// When the executor is asynchronous, the callback function needs to be recorded and executed after the executor completes
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)});this.failCallback.push(() = > {
setTimeout(() = > {
try {
const x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)}); }})return promise2;
}
finally(callback) {
return this.then(value= > {
const x = callback();
return MyPromise.resolve(x).then(() = > value)
}, error= > {
const x = callback();
return MyPromise.reject(x).then(undefined.() = > error)
})
}
catch(callback) {
this.then(undefined, callback);
}
static all(array) {
const result = [];
let i = 0;
return new MyPromise((resolve, reject) = > {
const addData = (key, value) = > {
result[key] = value;
i++;
if (i === array.length) {
resolve(result);
}
}
array.forEach((item, index) = > {
if (item instanceof MyPromise) {
item.then(value= > addData(index, value), error= > reject(error))
} else{ addData(index, item); }})})}static resolve(item) {
if (item instanceof MyPromise) {
return item;
} else {
return new MyPromise(resolve= > {
resolve(item)
})
}
}
static reject(error) {
return new MyPromise((resolve, reject) = > {
reject(error)
})
}
}
Copy the code