One, foreword

Do not toss not front end, in the present company for 3 years, each period of time will go to different companies interview, the purpose is to see the market dynamics, what requirements to the front end. The other is to measure how much they can be worth in the front-end market. Third, to consolidate knowledge and improve interview skills. Of course, can’t pick those you want to enter the company to do the experiment, like fortune factory, pig farm, they will have your interview record, affect the interview after, the gain is not worth the loss. Recently in the interview process, I was asked a platitudes topic, the realization of promise principle. So I decided to write an article about the promise source code implementation.

Ii. Use of PROMsie

Normal in the implementation of an API source code, the first is skilled use of the API, from the API to consider how to achieve the source code, this is the way I have been.

new MyPromise((resolve, reject) => {
	
}).then((data) => {
	// do something
}).then((data) => {
	// do something
}).catch((err) => {
	// do something
})
Copy the code

Three, source code implementation

A very simple example shows that a promise is a constructor that has several methods: resolve, reject, then, catch, resolve, and Reject to change the state and execute then or catch based on the state. So you can immediately write the connective structure of the promise

Class Promise {constructor (executor) {this. Status = 'pending' // pending pity, This. Reason = null // reject Cause this. OnResolvedCallbacks = [];  This. OnRejectedCallbacks = []; let resolve = (value) => { if (this.status ! == 'pending') { return } this.status = 'fulfilled' this.value = value this.onResolvedCallbacks.forEach(fn => fn(this.value)) } let reject = (reason) => { if (this.status ! == 'pending') { return } this.status = 'reject' this.reason = reason this.onResolvedCallbacks.forEach(fn => Fn (this.value))} try {executor(resolve, reject)} catch(err) {reject()}} then (onpity, Onrejected) {/ / using setTimeout to simulate asynchronous if (this. The status = = = 'pending') {this. OnResolvedCallbacks. Push (= > {setTimeout () () ( => { onfulfilled(this.value) }, 0) }) this.onRejectedCallbacks.push(() => { setTimeout(() => { onrejected(this.value) }, 0) }) } else if (this.status === 'fulfilled') { setTimeout(() => { onfulfilled(this.value) }, 0) } else { setTimeout(() => { onrejected(this.value) }, 0) } } catch (errHander) { this.then(null, errHander) } }Copy the code

A simple promise is done, but the runtime finds that it cannot be chained because the return value of then is not a PROMISE, and there is no THEN method, so an error is reported. So the solution is to return a new promise, so the question is, why a new promise and not return this?

4. Chain call

To ensure logical simplicity, the state of a promise can only change from pending to pity or reject, which is where the name of the promise comes from. If return this is used and the then callback fails, the state will still be fulfilled, and the promise will not catch the error. So let’s change the code

then (onfulfilled, onrejected) {
  let newPromise = new MyPromise((resolve, reject) => {
    if (this.status === 'pending') {
      this.onResolvedCallbacks.push(() => {
        setTimeout(() => {
          onfulfilled(this.value)
        }, 0)
      })
      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          onrejected(this.reason)
        }, 0)
      })
    } else if (this.status === 'fulfilled') {
      setTimeout(() => {
        let value = onfulfilled(this.value)
      	reject(value)
      }, 0)
    } else {
      setTimeout(() => {
        let reason = onrejected(this.reason)
      	reject(reason)
      }, 0)
    }
  })
  return newPromise
}
Copy the code

At this point, a simple promise has been implemented, including then and catch methods, which will suffice for an interview.

Five, the optimization

This is a big pity. Careful students may have found that if onfulfilled is a promise? We don’t want the result of then to be a promise, so we need to wait until that promise resolve to proceed with the THEN method. So let’s do it again

Function resolvePromise(promise, x, resolve, reject) {if ((typeof x === 'object' &&x! = null && x._proto_. Contructor === mypromse.contructor)) {// Let then = x.hen then. Call (x, x) ResolvePromsie (promise, y, resolve, reject), r => {reject(r); }) } else if(typeof x === 'function') { let value = x() resolvePromise(promise, value, resolve, This will be a pity, onpromise = new MyPromise((pity, onpromise)); reject) => { if (this.status === 'pending') { this.onResolvedCallbacks.push(() => { setTimeout(() => { let x = onfulfilled(this.value) resolvePromsie(newPromse, x, resolve, reject) }, 0) }) this.onRejectedCallbacks.push(() => { setTimeout(() => { let x = onrejected(this.reason) resolvePromsie(newPromse,  x, resolve, reject) }, 0) }) } else if (this.status === 'fulfilled') { setTimeout(() => { let value = onfulfilled(this.value) resolvePromsie(newPromse, value, resolve, reject) }, 0) } else { setTimeout(() => { let reason = onrejected(this.reason) resolvePromsie(newPromse, reason, resolve, reject) }, 0) } }) return newPromise }Copy the code

Six, summarized

Most of the time, we do not have to write promise source code in our daily work, but in order not to be seen as “skilled API workers”, or lu Yi Lu source code, followed by promise design ideas, improve programming ability. What’s more, almost every interviewer will ask, and while they don’t know if they will, it’s always good to be prepared.