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