preface
I heard the interview often, anyway, I have not encountered, just in case, first prepare for the preparation.
Promise core logic implementation
So let’s just use Promise briefly, assuming you all know how the PROMISE API works, right
let promise = new Promise((resolve, reject) = > {
resolve('success')
// reject(' reject ')
})
promise.then(value= > {
console.log(value) / / success
}, reason= > {
console.log(reason)
})
Copy the code
Initialize MyPromise
Promise is a class that instantiates a Promise with the new keyword and passes in an executor function that takes two arguments, both functions, and the state does not change once one of them is executed. The state of a Promise is pending. The state of a Promise is fullfilled. Successful status, Rejected: Indicates the failed status. The state can only be from Pending -> Fullfilled or Pending -> Rejected. Once the state is changed to Fullfilled or Rejected, it does not change. So when do you change states? Now let’s implement the source code
class MyPromise {
constructor(executor) {
// New Mypromise will execute executor immediately
// Executor has two methods: resolve, reject
executor(this.resolve, this.reject)
}
resolve = () = > {
}
reject = () = >{}}Copy the code
Add state for Mypromise
To start simple, we want to implement a MyPromise of our own. New passes a function and executes it immediately, so we pass in the executor method from constructor and execute it immediately. And resolve and reject are two executor parameters that correspond to two methods. Let’s keep knocking down
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
// The default state is wait
status = PENDING
constructor(executor){... } resolve =() = > {
// If the state is not pending, the execution will not proceed
if(this.status! == PENDING)return;
// Change the state when execute resolve
this.status = FULFILLED
}
reject = () = > {
// If the state is not pending, the execution will not proceed
if(this.status ! == PENDING)return;
// Modify the status when executing reject
this.status = REJECTED; }}Copy the code
Add the then method for MyPromise
Here we add the concept of state. First, we define three states, initialize one state as pending in the class, and determine whether the state changes before executing resolve. If it changes, the state is not executed. Then down
class MyPromise {
// The default state is wait
status = PENDING
value = undefined
reason = undefined
constructor(executor){... } resolve =value= >{...this.value = value
}
reject = reason= >{...this.reason = reason
}
then = (successCallback, failCallback) = > {
// Add two new callbacks. If the state is fullfilled, resolve is called and successCallback is called
// When we use then, we receive a value that is passed after the resolve execution,failCallbac
if(this.status === FULFILLED) successCallback(this.value)
else if(this.status === REJECTED) failCallback(this.value)
}
}
Copy the code
Then (value => console.log(value)) then(value => console.log(value))) This value is passed in the promise by calling resolve(‘ success ‘), so I define a value in MyPromise, Resolve assigns value to this.value, and successCallback gets the value, which we’ll do
let promise = new MyPromise((resolve, reject) = > {
resolve('success')
// reject(' reject ')
})
promise.then(value= > {
console.log(value) / / success
}, reason= > {
console.log(reason)
})
Copy the code
You will find that you have been able to print out the success, so far, the promise core logic is over, is not feel very easy 😎. The complete code above
Click me to expand the code at 👈
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
// The default state is wait
status = PENDING
value = undefined
reason = undefined
constructor(executor) {
// New Mypromise will execute executor immediately
// Executor has two methods: resolve, reject
executor(this.resolve, this.reject)
}
resolve = value= > {
// If the state is not pending, the execution will not proceed
if(this.status! == PENDING)return;
// Change the state when execute resolve
this.status = FULFILLED;
this.value = value
}
reject = reason= > {
// If the state is not pending, the execution will not proceed
if(this.status ! == PENDING)return;
// Modify the status when executing reject
this.status = REJECTED;
this.reason = reason
}
then = (successCallback, failCallback) = > {
// Add two new callbacks. If the state is fullfilled, resolve is called and successCallback is called
// When we use then, we receive a value that is passed after the resolve execution, similar to failCallback
if(this.status === FULFILLED) successCallback(this.value)
else if(this.status === REJECTED) failCallback(this.reason)
}
}
Copy the code
Adding asynchronous logic
Take a look at the sample code
let promise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('success')},200);
})
promise.then(value= > {
console.log(value) // Do not print anything
}, reason= > {
console.log(reason)
})
Copy the code
When we add an asynchrony to resolve, we find that console prints nothing. Why?
if(this.status === FULFILLED) successCallback(this.value)
else if(this.status === REJECTED) failCallback(this.value)
Copy the code
The new Promise is executed immediately after the action is completed. Then the state is still pending, and the state is fullfilled or Rejected Is executed, so now nothing is executed. Now let’s implement asynchronous operations
class MyPromise {... successCallback =undefined
failCallback = undefined
constructor(executor){... } resolve =value= >{...this.successCallback && this.successCallback(value)
}
reject = reason= >{...this.failCallback && this.failCallback(reason)
}
then = (successCallback, failCallback) = >{...else {
// Save successCallback and failCallback when Status is pending, and resolve when resolve is executed
this.successCallback = successCallback
this.failCallback = failCallback
}
}
}
Copy the code
First we define two callbacks. We add an else statement to then to say that when the state is pending, we save two callbacks and then call resolve asynchronously. If resolve does not have an asynchronous operation, it will not execute. If it does, it will execute and pass value to the callback.
let promise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('success')},200);
})
promise.then(value= > {
console.log(value) / / success
}, reason= > {
console.log(reason)
})
Copy the code
Then we will print it again and find that it will output normally. The complete code above is as follows
Click me to expand the code at 👈
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
// The default state is wait
status = PENDING
value = undefined
reason = undefined
constructor(executor) {
// New Mypromise will execute executor immediately
// Executor has two methods: resolve, reject
executor(this.resolve, this.reject)
}
resolve = value= > {
// If the state is not pending, the execution will not proceed
if(this.status! == PENDING)return;
// Change the state when execute resolve
this.status = FULFILLED;
this.value = value
}
reject = reason= > {
// If the state is not pending, the execution will not proceed
if(this.status ! == PENDING)return;
// Modify the status when executing reject
this.status = REJECTED;
this.reason = reason
}
then = (successCallback, failCallback) = > {
// Add two new callbacks. If the state is fullfilled, resolve is called and successCallback is called
// When we use then, we receive a value that is passed after the resolve execution, similar to failCallback
if(this.status === FULFILLED) successCallback(this.value)
else if(this.status === REJECTED) failCallback(this.reason)
}
}
Copy the code
Implement multiple calls to the THEN method (not chain calls)
Let’s look at another example
let promise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('success')},200);
})
promise.then(value= > {
console.log(value) // No output
}, reason= > {
console.log(reason)
})
promise.then(value= > {
console.log(value) // The output succeeded
}, reason= > {
console.log(reason)
})
Copy the code
The first execution of promise. Then will not execute resolve, which is the first execution of the promise. Then source code Promise. Then what did he do? If successCallback is saved, it overwrites the previous successCallback. Only the last “then” will be executed. So we’re going to solve this problem and go to code
class MyPromise {
// successCallback = undefined
// failCallback = undefined
// Modify successCallback and failCallback to arrays
successCallback = []
failCallback = []
constructor(executor){... } resolve =value= >{...// this.successCallback && this.successCallback(value)
while(this.successCallback.length) this.successCallback.shift()(value)
}
reject = reason= >{...// this.failCallback && this.failCallback(reason)
while(this.failCallback.length) this.failCallback.shift()(reason)
}
then = (successCallback, failCallback) = >{...else {
// Save successCallback and failCallback when Status is pending, and resolve when resolve is executed
// this.successCallback = successCallback
// this.failCallback = failCallback
// Push each callback into the array
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
}
}
Copy the code
Simply put, the callback function is stored in an array, Each time through the original object. Then will push a callback (note that only the asynchronous resolve will push, can think about why synchronous don’t need to push?) this time to perform the above case is found that both promise success
Click me to expand the code at 👈
const PENDING = 'pending'; / / wait for
const FULFILLED = 'fulfilled'; / / success
const REJECTED = 'rejected'; / / fail
class MyPromise {
// The default state is wait
status = PENDING
value = undefined
reason = undefined
// successCallback = undefined
// failCallback = undefined
// Modify successCallback and failCallback to arrays
successCallback = []
failCallback = []
constructor(executor) {
// New Mypromise will execute executor immediately
// Executor has two methods: resolve, reject
executor(this.resolve, this.reject)
}
resolve = value= > {
// If the state is not pending, the execution will not proceed
if(this.status! == PENDING)return;
// Change the state when execute resolve
this.status = FULFILLED;
this.value = value
// this.successCallback && this.successCallback(value)
while(this.successCallback.length) this.successCallback.shift()(value)
}
reject = reason= > {
// If the state is not pending, the execution will not proceed
if(this.status ! == PENDING)return;
// Modify the status when executing reject
this.status = REJECTED;
this.reason = reason
// this.failCallback && this.failCallback(reason)
while(this.failCallback.length) this.failCallback.shift()(reason)
}
then = (successCallback, failCallback) = > {
// Add two new callbacks. If the state is fullfilled, resolve is called and successCallback is called
// When we use then, we receive a value that is passed after the resolve execution, similar to failCallback
if(this.status === FULFILLED) successCallback(this.value)
else if(this.status === REJECTED) failCallback(this.reason)
else {
// Save successCallback and failCallback when Status is pending, and resolve when resolve is executed
// this.successCallback = successCallback
// this.failCallback = failCallback
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
}
}
let promise = new MyPromise((resolve, reject) = > {
setTimeout(() = > {
resolve('success')},200); }) promise.then(value= > {
console.log(value) / / success
}, reason= > {
console.log(reason)
})
promise.then(value= > {
console.log(value) / / success
}, reason= > {
console.log(reason)
})
Copy the code
Implement chain calls to THEN
Now the article is too long, and I’ll put it in the next one, which I think is the hardest part of making promise come true