Promise:
So let’s first create aMyPromise
类
class MyPromise {
constructor(executor) {
this.state = 'pending' / / state
this.value = undefined // Save resolve
this.error = undefined // Save the reject value
/ / resolve function
const resolve = value= > {
if (this.state === 'pending') {
this.state = 'fullFilled'
this.value = value
}
}
/ / reject function
const reject = error= > {
if (this.state === 'pending') {
this.state = 'rejected'
this.error = error
}
}
// Executes the function passed in via new MyPromise()
executor(resolve, reject)
}
/ / then method
then(onFullFilled, onRejected) {
// If the state is fullFilled, execute the resolve callback
if (this.state === 'fullFilled') {
onFullFilled(this.value)
}
// If the state is fullFilled, execute the reject callback
if (this.state === 'rejected') {
onRejected(this.error)
}
}
}
// Test basic functionality
new MyPromise((resolve, reject) = > {
if (Math.random() < 0.5) {
resolve('fullFilled')}else {
reject('rejected')
}
}).then(value= > {
console.log(value)
}, error= > {
console.log(error)
})
Copy the code
This code implements the simplest resolve and reject, but in a Promise, syntactic errors will be caught and reject will be triggered, so error trapping is required
Implement error capture
try {
// Executes the function passed in via new MyPromise()
executor(resolve, reject)
} catch (e) {
reject(e)
}
// Test the capture function
new MyPromise((resolve, reject) = > {
// Intentionally print an undefined value
console.log(a)
}).then(value= > {
console.log(value)
}, error= > {
// Will trigger the failed callback function
console.log(error)
})
Copy the code
This catches errors and fires reject, but if a Promise fires resolve/ Reject asynchronously, success and failure callbacks in THEN won’t be triggered properly, so you need to save success and failure callbacks in advance using a publish-subscribe mechanism. The callback is then triggered when resolve/ Reject fires
Implement asynchronous triggeringresolve/reject
.this.onResolvedCallback = [] // Save the resolve callback
this.onRejectedCallback = [] // Save the reject callback
/ / resolve function
const resolve = value= > {
if (this.state === 'pending') {
this.state = 'fullFilled'
this.value = value
this.onResolvedCallback.forEach(fn= > fn())
}
}
/ / reject function
const reject = error= > {
if (this.state === 'pending') {
this.state = 'rejected'
this.error = error
this.onRejectedCallback.forEach(fn= > fn())
}
}
/ / then method
then(onFullFilled, onRejected){...// If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
if (this.state === 'pending') {
this.onResolvedCallback.push(() = > {
onFullFilled(this.value)
})
this.onRejectedCallback.push(() = > {
onRejected(this.error)
})
}
}
// Test asynchronous code
new MyPromise((resolve, reject) = > {
setTimeout(() = > {
if (Math.random() < 0.5) {
resolve(10)}else {
reject(-10)}},1000)
}).then(value= > {
console.log(value)
}, error= > {
console.log(error)
})
Copy the code
The successful and failed callbacks in THEN can also be fired asynchronously if resolve/ Reject is fired, and the next step is to implement the chained calls to then
implementationthen
The chain call to
/ / then method
then(onFullFilled, onRejected) {
let x
return new MyPromise((resolve, reject) = > {
// If the state is fullFilled, execute the resolve callback
if (this.state === 'fullFilled') {
x = onFullFilled(this.value)
resolve(x)
}
// If the state is fullFilled, execute the reject callback
if (this.state === 'rejected') {
x = onRejected(this.error)
resolve(x)
}
// If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
if (this.state === 'pending') {
this.onResolvedCallback.push(() = > {
x = onFullFilled(this.value)
resolve(x)
})
this.onRejectedCallback.push(() = > {
x = onRejected(this.error)
resolve(x)
})
}
})
}
// Test chained calls
const myPromise = new MyPromise((resolve, reject) = > {
if (Math.random() < 0.5) {
resolve(10)}else {
reject(-10)
}
})
myPromise.then(value= > {
console.log('sucess:', value)
return value + 2
}, error= > {
console.log('fail:', error)
return error - 2
}).then(value= > {
console.log('sucess:', value)
return value + 8
}, error= > {
console.log('fail:', error)
return error - 8
}).then(value= > {
console.log('sucess:', value)
return value + 10
}, error= > {
console.log('fail:', error)
return error - 10
})
Copy the code
This implements the chain of calls to THEN, and ensures that each successful and failed callback to then returns a promise object, followed by an error-catching mechanism
then
Chain operation adds error capture
/ / then method
then(onFullFilled, onRejected) {
let x
return new MyPromise((resolve, reject) = > {
// If the state is fullFilled, execute the resolve callback
if (this.state === 'fullFilled') {
// Add an error-catching mechanism
try {
x = onFullFilled(this.value)
resolve(x)
} catch (e) {
reject(e)
}
}
// If the state is fullFilled, execute the reject callback
if (this.state === 'rejected') {
// Add an error-catching mechanism
try {
x = onRejected(this.error)
resolve(x)
} catch (e) {
reject(e)
}
}
// If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
if (this.state === 'pending') {
this.onResolvedCallback.push(() = > {
// Add an error-catching mechanism
try {
x = onFullFilled(this.value)
resolve(x)
} catch (e) {
reject(e)
}
})
this.onRejectedCallback.push(() = > {
// Add an error-catching mechanism
try {
x = onRejected(this.error)
resolve(x)
} catch (e) {
reject(e)
}
})
}
})
}
// Test the error trapping function in chained calls
const myPromise = new MyPromise((resolve, reject) = > {
if (Math.random() < 0.5) {
resolve(10)}else {
reject(-10)
}
})
myPromise.then(value= > {
// Intentionally print an undefined value
console.log(a)
return value + 2
}, error= > {
// Intentionally print an undefined value
console.log(a)
return error - 2
}).then(value= > {
console.log('sucess:', value)
}, error= > {
// Will trigger the failed callback function
console.log('fail:', error)
})
Copy the code
Once this is done, there is a problem. If I actively return a promise in the success or failure callback of then, how do I deal with the relationship between that promise and the promise returned by default?
Compatible return value ispromise
Case of object
/ / then method
then(onFullFilled, onRejected) {
const promise = new MyPromise((resolve, reject) = > {
let x
// If the state is fullFilled, execute the resolve callback
if (this.state === 'fullFilled') {
try {
x = onFullFilled(this.value)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
}
// If the status is Rejected, the reject callback is executed
if (this.state === 'rejected') {
try {
x = onRejected(this.error)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
}
// If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
if (this.state === 'pending') {
this.onResolvedCallback.push(() = > {
try {
x = onFullFilled(this.value)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
})
this.onRejectedCallback.push(() = > {
try {
x = onRejected(this.error)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
})
}
})
function resolvePromise(x, resolve, reject) {
If the return value is a Promise object
if (typeof x === 'object'&& x ! = =null && typeof x.then === 'function') {
x.then(value= > {
resolve(value)
}, err= > {
reject(err)
})
} else {
resolve(x)
}
}
return promise
}
// Test the case where the return value is a Promise object
const myPromise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
if (Math.random() < 0.5) {
resolve(10)}else {
reject(-10)
}
})
})
myPromise.then(value= > {
console.log('sucess0:', value)
// Actively return a Promise object
return new MyPromise((resolve, reject) = > {
resolve(Awesome!)})},error= > {
console.log('fail0:', error)
return new MyPromise((resolve, reject) = > {
resolve(222)
})
})
.then(value= > {
console.log('sucess1:', value)
return value
}, error= > {
console.log('fail1:', error)
return error
})
.then(value= > {
console.log('sucess2:', value)
return value
}, error= > {
console.log('fail2:', error)
return error
})
Copy the code
Add a resolvePromise method to determine the type of the returned object. If it is a Promise object, resolve the resolved value again. However, if a promise object is returned with nested promises, recursive processing is required
Recursive processing of the return value of the Promise object
function resolvePromise(x, resolve, reject) {
If the return value is a Promise object
if (typeof x === 'object'&& x ! = =null && typeof x.then === 'function') {
console.log('aaa')
x.then(value= > {
// Recursively process the promise return value
resolvePromise(value, resolve, reject)
}, err= > {
reject(err)
})
} else {
console.log('bbb')
resolve(x)
}
}
// Test the case where the return value is a Promise object
const myPromise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
if (Math.random() < 0.5) {
resolve(10)}else {
reject(-10)
}
})
})
myPromise.then(value= > {
console.log('sucess0:', value)
return new MyPromise((resolve, reject) = > {
// Nested multiple promises
resolve(new MyPromise((resolve, reject) = > {
resolve(Awesome!)})}})),error= > {
console.log('fail0:', error)
return new MyPromise((resolve, reject) = > {
resolve(222)
})
})
.then(value= > {
console.log('sucess1:', value)
return value
}, error= > {
console.log('fail1:', error)
return error
})
.then(value= > {
console.log('sucess2:', value)
return value
}, error= > {
console.log('fail2:', error)
return error
})
Copy the code
Complete code
class MyPromise {
constructor(executor) {
this.state = 'pending' / / state
this.value = undefined // Save resolve
this.error = undefined // Save the reject value
this.onResolvedCallback = [] // Save the resolve callback
this.onRejectedCallback = [] // Save the reject callback
/ / resolve function
const resolve = value= > {
if (this.state === 'pending') {
this.state = 'fullFilled'
this.value = value
this.onResolvedCallback.forEach(fn= > fn())
}
}
/ / reject function
const reject = error= > {
if (this.state === 'pending') {
this.state = 'rejected'
this.error = error
this.onRejectedCallback.forEach(fn= > fn())
}
}
try {
// Executes the function passed in via new MyPromise()
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
/ / then method
then(onFullFilled, onRejected) {
const promise = new MyPromise((resolve, reject) = > {
let x
// If the state is fullFilled, execute the resolve callback
if (this.state === 'fullFilled') {
try {
x = onFullFilled(this.value)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
}
// If the status is Rejected, the reject callback is executed
if (this.state === 'rejected') {
try {
x = onRejected(this.error)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
}
// If the status is pending, resolve or reject is asynchronously executed. Save the callback and postpone the execution
if (this.state === 'pending') {
this.onResolvedCallback.push(() = > {
try {
x = onFullFilled(this.value)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
})
this.onRejectedCallback.push(() = > {
try {
x = onRejected(this.error)
resolvePromise(x, resolve, reject)
} catch (err) {
reject(err)
}
})
}
})
function resolvePromise(x, resolve, reject) {
If the return value is a Promise object
if (typeof x === 'object'&& x ! = =null && typeof x.then === 'function') {
x.then(value= > {
resolvePromise(value, resolve, reject)
}, err= > {
reject(err)
})
} else {
resolve(x)
}
}
return promise
}
}
Copy the code