Promise,
Why do WE need Promise
JavaScript is a single-threaded language, so in the early days we dealt with asynchronous scenarios mostly through callback functions. For example, sending an Ajax request in a browser is a common asynchronous scenario, where the request is sent and the server responds some time before we get the result. If we want to perform an operation after the asynchrony ends, the only way to do so is through a callback function.
const dynamicFunc = function (cb) {
setTimeout(() = > {
cb()
}, 1000)
}
dynamicFunc(function () {
console.log(123)})Copy the code
In this example dynamicFunc is an asynchronous function. SetTimeout will put the cb function into the event queue after 1s, and call the CB function when the main thread is finished executing. Following the above call, the result 123 will be printed after a delay of 1s. Similarly, if there is further output at the end of the asynchronous function, multiple asynchronous functions need to be nested, which is not good for subsequent maintenance.
How is Promise used
In an advanced browser environment that supports ES6, we create a Promise instance with New Promise(). This constructor takes a function that takes two arguments, resolve and reject, to change the state of the current instance to completed or rejected.
function promise1() {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
console.log('Output after 1s')
resolve();
}, 1000)})}function promise2() {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
console.log('Output after 2s')
resolve();
}, 2000)})}Copy the code
Promise1 () => promise2(); promise1() => promise2(); promise1() => promise2();
After executing in the browser, you can see that after 1s comes 1s output, after 2s comes 2s output. In this example, we can see that the current promise will execute the next promise function in the then method if the state changes to complete (resolve method executed).
Similarly, if a promise becomes rejected (reject method executed), it goes into subsequent exception handlers.
function promise3() {
return new Promise(function (resolve, reject) {
var random = Math.random() * 10;
setTimeout(function () {
if (random >= 5) {
resolve(random);
} else{ reject(random); }},1000);
});
}
var onResolve = function (val) {
console.log('Done: The output number is:', val);
};
var onReject = function (val) {
console.log('Rejected: the output number is:', val);
}
promise3().then(onResolve, onReject);
// A promise whose state becomes rejected can be intercepted using the catch method
promise3().catch(onReject).then(onResolve);
// You can also intercept a rejected promise with a try catch
try {
promise3().then(onResolve);
} catch (e) {
onReject(e);
}
Copy the code
This example uses three ways to intercept promises that eventually become rejected: using the second argument to then, using the.catch method to catch exceptions thrown by the promise ahead, and using a try catch to intercept exceptions thrown by the promise in a block of code.
We also found that when we call resolve and Reject when we change the promise state, we can also pass arguments to the next function executed in the THEN. In this example, we pass the randomly generated number to resolve and reject, so that we can get the value when we execute the function in THEN.
Conclusion:
- Promise has three states,
ongoing
Has been completed
Has refused to
, the state in progress can be changed to completed or rejected, and no further changes can be made after the state has been changed (for example, it cannot be changed from Completed to rejected) - The Promise constructor in ES6 requires passing in a function, taking two function arguments, and changing the current Promise after the first argument
Has been completed
State, which becomes when the second argument is executedHas refused to
state - The. Then method allows you to continue executing the next function or promise when the previous promise becomes completed. At the same time, you pass an argument through resolve or reject to pass an initial value to the next function or promise
- Rejected promises can then be caught using either the. Catch method or the second argument to the. Then method or a try catch
Promise specification interpretation
Any object or function that meets the promise specification can become A promise. Promises /A+
Above, we learned how to use the whole promise, how to create a promise, how to use it, and how to modify the callback function into a promise. In this section, we will go through promises/A+ specifications in detail to understand the details in the process of using promises from the specification level.
The term
- Promise: Promise is a possession
then
Method that behaves in accordance with this specification - Having the then method (thenable) : is a definition
then
The object or function of a method - Value: any valid JavaScript value (including undefined, thenable, and promise)
- Exception: Yes
throw
A value thrown by the statement - Reason: indicates a reason for rejecting a promise
requirements
The state of the promise
The current state of a Promise must be one of three states: Pending, Fulfilled, and Rejected.
- In the wait state, a promise must satisfy one condition: it can be
Has been completed
orHas refused to
- When a promise is completed, it must satisfy the following conditions: 1. It cannot change into any other state 2. Must have an immutable value
- When a promise is rejected, the following conditions must be met: 1. It cannot change into any other state 2. There must be an immutable cause
There must be a then method
A promise must provide a THEN method to access its current value and reason. The promise’s then method accepts two parameters: Promise. Then (onFulfilled, onRejected), both of which are optional parameters, and they are functions. If onFulfilled or onRejected is not a function, you need to ignore them.
- if
onFulfilled
It’s a function- when
promise
It must be called after execution, and its first argument is the result of a promise - when
promise
It cannot be called until execution ends - It cannot be invoked more than once
- when
- if
onRejected
It’s a function- when
promise
The reason why it must be invoked if the execution is rejected, and its first argument is a promise - when
promise
It cannot be called until execution is rejected - It cannot be invoked more than once
- when
- Should not be called until the execution context stack contains only the platform code
onFulfilled
oronRejected
onFulfilled
andonRejected
Must be called as a normal function (i.e., a non-instantiated call, such that the inside of the functionthis
Point to window in non-strict mode)then
The method can be the samepromise
Call several times- when
promise
When successfully executed, allonFulfilled
Callbacks must be made in the order in which they were registered - when
promise
When rejected, allonRejected
Callbacks must be made in the order in which they were registered
- when
then
Method must return onepromise
objectpromise2 = promise1.then(onFulfilled, onRejected)
- As long as
onFulfilled
oronRejected
Return a valuex
Promise2 will enter the ondepressing state - As long as
onFulfilled
oronRejected
Throw an exceptione
, promise2 must reject execution and return a reasone
- As long as
- if
onFulfilled
Is not a function andpromise1
The state becomes completed,promise2
Must execute successfully and return the same value - if
onRejected
Is not a function andpromise1
The status becomes Rejected,promise2
You must perform a reject callback and return the same cause
var promise1 = new Promise((resolve, reject) = > { reject(); });
promise1
.then(null.function () {
return 123;
})
.then(null.null)
.then(null.null)
.then(
() = > {
console.log('Promise2 completed');
},
() = > {
console.log('Promise2 has been rejected');
});
Copy the code
Promise’s resolution process
** Promise resolution is an abstract operation that takes a promise and a value, which we express as [[Resolve]](promise, x).
promise.then(x= > {
console.log('will execute this function, passing in the value of the x variable:', x)
})
Copy the code
If X has a then method and looks like a Promise, the resolver tries to make the Promise accept x’s state; Otherwise it implements the promise with the value of x.
- if
promise
andx
To point to the same objectTypeError
Refuse to perform for reasonpromise
- if
x
forpromise
- if
x
In the waiting state,promise
Must remain in wait state untilx
To be carried out or rejected - if
x
In the execution state, execute with the same valuepromise
- if
x
In the rejection state, reject for the same reasonpromise
- if
var promise1 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(1);
resolve();
}, 1000)}); }var promise2 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(2);
resolve();
}, 2000);
});
}
promise1()
.then(function () {
return promise2(); // An instance of promise is returned
})
.then(function () { console.log('Done')},function () { console.log('Rejected')});Copy the code
- if
x
For Object or function (uncommon)- Try executing x. teng first
- An error is thrown if the value of x. Chen is taken
e
, thee
Reject for a reasonpromise
- if
then
Theta is a function of thetax
As the scope of the functionthis
The call. Pass two callback functions as arguments, the first of which is calledresolvePromise
The second one is calledrejectPromise
:- if
resolvePromise
In order to valuey
Run ‘[[Resolve]](promise, y) - if
rejectPromise
To according to ther
Is called with an argument, then with an argumentr
Refused topromise
- if
resolvePromise
andrejectPromise
Are called, or are called by the same parameter more than once, the first call is preferred and other calls are ignored - If the call
then
Method throws an exceptione
- if
resolvePromise
orrejectPromise
If yes, ignore it - Or otherwise
e
Refusal on grounds of proofpromise
- if
- if
- if
then
Is not a function of thetax
For the parameter will bepromise
Changes to the completed state
- if
x
Is not an object or a functionx
For the parameter will bepromise
To the completed state ** (important and common) **
Static methods on the Promise constructor
Promise.resolve
Return a Promise instance with its state set to completed and its result passed in as the value of the Promise instance
var promise = Promise.resolve(123);
promise
.then(function (val) {
console.log('????? ', val);
});
// 123 completed
Copy the code
Similarly, the promise.resolve argument can handle objects, functions, and so on in the same way as described in the specification above.
Promise.reject
Return an instance of Promise with its state set to rejected and also pass its result as the reason to the onRejected function
var promise = Promise.reject(123);
promise
.then(null.function (val) {
console.log('Rejected', val);
});
// 123 has been rejected
Copy the code
Promise.all
Return a Promise instance that receives an array of multiple Promise instances. When all the promise instances are in the completed state, it goes to the completed state, otherwise it goes to the rejected state.
var promise1 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(1);
resolve();
}, 1000)}); }var promise2 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(2);
resolve();
}, 2000);
});
}
Promise.all([promise1(), promise2()])
.then(function () {
console.log('All promises have been fulfilled');
});
Copy the code
Note that multiple promises are made at the same time, i.e. in the example above, after waiting 1s to print 1, after waiting 1s to print 2 and ‘All promises are completed’.
Promise.race
Return a Promise instance and receive an array containing multiple Promise instances. When a Promise instance state changes, it goes into that state and cannot be changed. Here, all promise instances are competing, and only the first promise to enter the changed state is selected.
var promise1 = function () { return new Promise(function (resolve) { setTimeout(function () { console.log(1); resolve(1); }, 1000)}); } var promise2 = function () { return new Promise(function (resolve) { setTimeout(function () { console.log(2); resolve(2); }, 2000); }); } promise.race ([promise1(), promise2()]). Then (function (val) {console.log(' one Promise has changed: ', val); });Copy the code
Make a simple promise
Promise class core logic implementation
- A Promise is a class that, when instantiated, passes an executor function that executes immediately
- There are three states in Promise: success (depressing) Failure (Rejected) waiting (pending).
- When the resolve method is executed, the state changes from pending to depressing; when the reject method is executed, the state changes from pending to Rejected. Once the state is determined, it cannot be changed again
- The then method is defined in the prototype object and takes two parameters, a successful callback and a failed callback
- The then method determines the state. If the state is successful, a callback function is called (the value passed successfully), and if the state is unsuccessful, a callback function is called (the reason for the failure).
// The purpose of defining constants is: 1. To represent different states of promise 2. You can make the editor have code hints (haha)
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
}
then(successCb, failCb) {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
successCb(this.successData) // Call a successful callback to return the value
} else if (this.status === REJECTED) { // Synchronous call
failCb(this.failReason) // Call the failure callback to return the cause}}}Copy the code
const promise = new MyPromise((resolve, reject) = > {
resolve('success')
// reject('fail')
});
promise.then(val= > {
console.log(val)
}, reason= > {
console.log(reason)
})
Copy the code
Add asynchronous logic to the Promise
The above code is not handled asynchronously, which would be a problem if there was asynchronous logic
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = undefined // Store the successful callback function
failCallback = undefined // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
this.successCallback && this.successCallback(this.successData) // Asynchronous logic calls a successful callback
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
this.failCallback && this.failCallback(this.failReason) // Asynchronous logic invokes the failed callback
}
then(successCb, failCb) {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
successCb(this.successData) // Call a successful callback to return the value
} else if (this.status === REJECTED) { // Synchronous call
failCb(this.failReason) // Call the failure callback to return the cause
} else { // Asynchronous invocation
this.successCallback = successCb // Store a successful callback
this.failCallback = failCb // Storage failed callback}}}Copy the code
const promise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
// resolve('success')
reject('fail')},1500)}); promise.then(val= > {
console.log(val)
}, reason= > {
console.log(reason)
})
Copy the code
The implementation Promise then method is called multiple times
- Promise’s then method can be called multiple times.
- The following example has three then callbacks; if it is a synchronous callback, it simply returns the current value.
- If the callback is asynchronous, the successful and failed callbacks need to be saved with different values because they are not the same.
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while(this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()(this.successData)
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while(this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
successCb(this.successData) // Call a successful callback to return the value
} else if (this.status === REJECTED) { // Synchronous call
failCb(this.failReason) // Call the failure callback to return the cause
} else { // Asynchronous invocation
this.successCallback.push(successCb) // Store a successful callback
this.failCallback.push(failCb) // Storage failed callback}}}Copy the code
Test examples:
const promise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('success')
// reject('fail')
}, 1500)}); promise.then(val= > {
console.log(val, 11)},reason= > {
console.log(reason, 11)
})
promise.then(val= > {
console.log(val, 22)},reason= > {
console.log(reason, 22)
})
promise.then(val= > {
console.log(val, 33)},reason= > {
console.log(reason, 33)})Copy the code
Chain calls to implement the Promise then method
- Promise’s then methods can be called chained, and the value of the subsequent then method’s callback parameter is the return value of the previous THEN method’s callback.
- The then method callback function parameter transfer includes two cases: 1. The parameter is the common value 2. The argument is another Promise object
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()(this.successData)
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
const s = successCb(this.successData) // Call a successful callback to return the value
// Determine whether p is a normal value or a promise object
// If the value is normal, call resolve directly
// If it is a Promise object, resolve or reject is called based on the result returned by the Promise object
parsePromiseStatus(s, resolve, reject)
} else if (this.status === REJECTED) { // Synchronous call
const f = failCb(this.failReason) // Call the failure callback to return the cause
parsePromiseStatus(f, resolve, reject)
} else { // Asynchronous invocation
this.successCallback.push(successCb) // Store a successful callback
this.failCallback.push(failCb) // Storage failed callback}})return promise
}
}
function parsePromiseStatus(p, resolve, reject) {
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
const promise = new MyPromise((resolve, reject) = > {
resolve('success') // So far, only synchronization is handled
});
function anther(n) {
return new MyPromise((resolve, reject) = > {
resolve('anther' + (n || ' '))})}const p = promise.then(val= > {
console.log('val: ', val)
// return '2222'
return anther()
}, reason= > {
console.log('reason', reason)
return anther(2)
}).then(val= > {
console.log('val2: ', val)
}, reason= > {
console.log('reason2: ', reason)
})
Copy the code
Then method chain calls recognize the return promise object itself
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()(this.successData)
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > { // The reason for using setTimeout: If you do not use setTimeout, the method will not be executed and the return promise cannot be obtained
const p = successCb(this.successData) // Call a successful callback to return the value
// Determine whether p is a normal value or a promise object
// If the value is normal, call resolve directly
// If it is a Promise object, resolve or reject is called based on the result returned by the Promise object
parsePromiseStatus(promise, p, resolve, reject)
}, 0)}else if (this.status === REJECTED) { // Synchronous call
failCb(this.failReason) // Call the failure callback to return the cause
} else { // Asynchronous invocation
this.successCallback.push(successCb) // Store a successful callback
this.failCallback.push(failCb) // Storage failed callback}})return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
const promise = new MyPromise((resolve, reject) = > {
resolve('success')});const p = promise.then(val= > {
console.log(val, 'resolved')
return p
}, reason= > {
console.log(reason, 'rejected')
})
p.then(val= > {
console.log(val, 22)},reason= > {
console.log(reason.message)
})
Copy the code
Error trapping
It can be divided into two types: 1. Error capture of the actuator; 2. Error capture of the execution of then
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()(this.successData)
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(successCb) // Store a successful callback
this.failCallback.push(failCb) // Storage failed callback}})return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
const promise = new MyPromise((resolve, reject) = > {
reject('success')
// throw new Error('executor error')
});
promise.then(val= > {
console.log(val, 'resolved')},reason= > {
console.log(reason, 'rejected')
throw new Error('then method error')
}).then(val= > {
console.log(val, 'then2')},reason= > {
console.log(reason.message)
})
Copy the code
Chained invocation in asynchronous state — PROMISE calls resolve or reject asynchronously
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
const promise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('success')},1000)}); promise.then(val= > {
console.log(val, 'resolved')
return 'xxx'
}, reason= > {
console.log(reason, 'rejected')
}).then(val= > {
console.log(val, 'then2')},reason= > {
console.log(reason.message)
})
Copy the code
Makes the arguments of the then method optional
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value= > value) // Use a callback if there is a callback, assign a function if there is no callback
failCb = failCb || (reason= > { throw reason })
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
const promise = new MyPromise((resolve, reject) = > {
// resolve('success')
reject('fail')}); promise.then().then().then(val= > {
console.log('resolved: ', val)
}, reason= > {
console.log('rejected: ', reason)
})
Copy the code
Promise.all implementation of the method
- The all method accepts an array, each element of which can be a normal value or a Promise object
- The order of the elements in the array is the order of the results
- If all values in the array are successful, then the function in the array is regarded as a success callback, and if one value is failed, then the function in the array is regarded as a failure callback
- The all method is called directly by the class, so all must be a static method of the class
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value= > value) // Use a callback if there is a callback, assign a function if there is no callback
failCb = failCb || (reason= > { throw reason })
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) = > {
function addArrayEle(key, value) {
result[key] = value
count++
// The length of the counter is the same as that of the array
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > addArrayEle(i, value), reason= > reject(reason))
} else {
/ / common values
addArrayEle(i, current)
}
}
})
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
function p1() {
return new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('p1')},2000)})}function p2() {
return new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('p2')},1000)
})
}
MyPromise.all(['a'.'b', p1(), 'c', p2()]).then(val= > {
console.log('val: ', val) // ["a", "b", "p1", "c", "p2"]
})
Copy the code
Implementation of the promise.race method
- The RACE method receives an array, and each element can be a normal value or a promise object
- If a common value exists, it is returned immediately. When all elements are Promise objects, if an instance state changes, it enters that state and cannot be changed
- Here, all promise instances are competing, and only the first promise to enter the changed state is selected, or the normal promise is selected
- The race method is called directly by the class, so all must be a static method of the class
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value= > value) // Use a callback if there is a callback, assign a function if there is no callback
failCb = failCb || (reason= > { throw reason })
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) = > {
function addArrayEle(key, value) {
result[key] = value
count++
// The length of the counter is the same as that of the array
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > addArrayEle(i, value), reason= > reject(reason))
} else {
/ / common values
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) = > {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > resolve(value), reason= > reject(reason))
} else {
resolve(current)
}
}
})
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
function p1() {
return new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('p1')},3000)})}function p2() {
return new MyPromise((resolve, reject) = > {
setTimeout(() = > {
reject('p2')},1000)
})
}
MyPromise.race(['b', p1(), 'a', p2()]).then(val= > {
console.log('val: ', val); // val: b
}, reason= > {
console.log('reason: ', reason)
})
Copy the code
Implementation of the promise.resolve method
- If the argument is a Promise object, it returns directly; If it is a value, a promise object is generated to return the value
- Resolve is a static method of the class
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value= > value) // Use a callback if there is a callback, assign a function if there is no callback
failCb = failCb || (reason= > { throw reason })
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) = > {
function addArrayEle(key, value) {
result[key] = value
count++
// The length of the counter is the same as that of the array
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > addArrayEle(i, value), reason= > reject(reason))
} else {
/ / common values
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) = > {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > resolve(value), reason= > reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if(value instanceof MyPromise) {
return value
}
return new MyPromise(resolve= > resolve(value))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
function p1() {
return new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('p1')},2000)
})
}
MyPromise.resolve(2000).then(val= > {
console.log('val: ', val) / / 2000
})
MyPromise.resolve(p1()).then(val= > {
console.log('val: ', val) // 'p1'
})
Copy the code
Promise. Reject method implementation
- If the argument is a Promise object, it returns directly; If it is a value, a promise object is generated to return the value
- Resolve is a static method of the class
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value= > value) // Use a callback if there is a callback, assign a function if there is no callback
failCb = failCb || (reason= > { throw reason })
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) = > {
function addArrayEle(key, value) {
result[key] = value
count++
// The length of the counter is the same as that of the array
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > addArrayEle(i, value), reason= > reject(reason))
} else {
/ / common values
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) = > {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > resolve(value), reason= > reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve= > resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) = > reject(reason))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
MyPromise.reject(1234).then(null.val= > {
console.log('val: ', val) // val: 123
})
Copy the code
Finally method implementation
- Used on prototype objects, so not static methods
- Finally executes whether the current state is successful or failed
- You can call the then method after the finally method to get the result
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value= > value) // Use a callback if there is a callback, assign a function if there is no callback
failCb = failCb || (reason= > { throw reason })
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
finally(callback) {
return this.then(value= > {
return MyPromise.resolve(callback()).then(() = > value)
}, reason= > {
return MyPromise.resolve(callback()).then(() = > { throw reason })
})
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) = > {
function addArrayEle(key, value) {
result[key] = value
count++
// The length of the counter is the same as that of the array
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > addArrayEle(i, value), reason= > reject(reason))
} else {
/ / common values
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) = > {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > resolve(value), reason= > reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve= > resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) = > reject(reason))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
function p1() {
return new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('p1')},2000)})}function p2() {
return new MyPromise((resolve, reject) = > {
reject('p1')
})
}
p2().finally(() = > {
console.log('finally')
return p1()
}).then(val= > {
console.log('resolve: ', val)
}, reason= > {
console.log('reject: ', reason)
})
Copy the code
Implementation of the catch method
- Used on prototype objects, so not static methods
- Call the then method directly, passing undefined as the first argument and Reason as the second
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // The instance attribute is used to indicate the promise state
successData = undefined // Store the parameters that resolve passes after success
failReason = undefined // Store the reject argument passed after a failure
successCallback = [] // Store the successful callback function
failCallback = [] // Store the failed callback function
resolve = (val) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = FULFILLED // Change the status to success
this.successData = val // Store the value after success
while (this.successCallback.length) { // Asynchronous logic calls a successful callback
this.successCallback.shift()()
}
}
reject = (reason) = > {
if (this.status ! == PENDING)return // Execution continues only when the status is pending
this.status = REJECTED // Change the status to failed
this.failReason = reason // Store the value after the failure
while (this.failCallback.length) { // Asynchronous logic invokes the failed callback
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value= > value) // Use a callback if there is a callback, assign a function if there is no callback
failCb = failCb || (reason= > { throw reason })
const promise = new MyPromise((resolve, reject) = > {
// Determine the status
if (this.status === FULFILLED) { // Synchronous call
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) { // Synchronous call
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else { // Asynchronous invocation
this.successCallback.push(() = > {
setTimeout(() = > {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Store a successful callback
this.failCallback.push(() = > {
setTimeout(() = > {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})// Storage failed callback}})return promise
}
finally(callback) {
return this.then(value= > {
return MyPromise.resolve(callback()).then(() = > value)
}, reason= > {
return MyPromise.resolve(callback()).then(() = > { throw reason })
})
}
catch(failCallback) {
return this.then(undefined, failCallback);
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) = > {
function addArrayEle(key, value) {
result[key] = value
count++
// The length of the counter is the same as that of the array
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > addArrayEle(i, value), reason= > reject(reason))
} else {
/ / common values
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) = > {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
/ / promise object
current.then(value= > resolve(value), reason= > reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve= > resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) = > reject(reason))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
Copy the code
Test examples:
function p2() {
return new MyPromise((resolve, reject) = > {
reject('p2 failed')
})
}
p2().then(val= > {
console.log('resolve: ', val)
}).catch(reason= > {
console.log('fail: ', reason) // fail: p2 failed
})
Copy the code