Today we’re going to play with Promise, step-by-step analysis.

  • Original Promise Effect
let promise = new Promise((resolve, reject) => resolve("success"));

promise.then(msg => console.log(msg));
Copy the code

  • Customize a Pomise
Class MyPromise {constructor(func) {this.callbacks = [] // bind this to const resolve = this.resolve.bind(this) func(resolve) } resolve(e) { this.callbacks.forEach(cb => cb(e)) } reject() { console.error('reject') } then(cb) { this.callbacks.push(cb) } } new MyPromise((resolve, _) => setTimeout(() => resolve('success'), 0)).then(e => console.log(e))Copy the code
  • The execution result

  • At this point it looks like the function is implemented, but whennew MyPromiseWhen theasynchronousMethods becomesynchronousMethod, at this pointthenCannot print a value in a method, such as:
new MyPromise((resolve, _) => resolve('success')).then(e => console.log(e))
Copy the code
  • This is the time to find a way tothenThe function in the method is put inresolveMethod, so take the browser event trigger thread, add the event to the queue to be processed JS task queue, wait for the JS engine processing, letresolveAt the time of executionthenMethod’s callback function already has an array of callbackscallbacks, such assetTimeoutMethods. There is a question here, is not just removed, how to add haha… Yes, but in a different place. But this is a microtaskqueueMicrotask, andsetTimeoutMacro tasks have a higher priority than microtasks, such as:
Class MyPromise {constructor(func) {this.callbacks = [] const resolve = this.resolve.bind(this) // QueueMicrotask (() => func(resolve))} resolve(e) {this.callbacks. ForEach (cb => cb(e))} reject() { console.error('reject') } then(cb) { this.callbacks.push(cb) } } new MyPromise((resolve, _) => resolve('success')).then(e => console.log(e))Copy the code
  • The familiar results are back. If an exception occurs in the middle of execution, it is caught and returnedreject, such as:
try {
      queueMicrotask(() => func(resolve))
} catch (error) {
      this.reject()
}
Copy the code
  • And then somebody said, there’s only onethenMethods, so manythenWhat about the method? Easy. Chain call. InthenIn the methodreturn this, such as:
Then (cb) {this.callbacks. Push (cb) // Return this}Copy the code
  • Output code
new MyPromise((resolve, _) => resolve('success')).then(e => console.log(e)).then(e => console.log(e))
Copy the code
  • The execution result

  • It looks like you can execute multiplethenMethod, but there are problems, careful partners foundthenThe result of the method is the same every time it is executed, and has not changed since the last time it was executed. For example:

  • twothenAll the data we get from the method is1. So want tothenThe value returned by the method is saved
Class MyPromise {constructor(func) {// initialize this. Value = null; Callbacks = [] // bind this to const resolve = this.resolvie.bind (this) queueMicrotask(() => func(resolve))} resolve(e) {this.value = e this.callbacks. ForEach (cb => {let newValue = cb(this.value) // Store the value returned by the then method this.value = newValue }) } reject() { console.error('reject') } then(cb) { this.callbacks.push(cb) return this } }Copy the code
  • The execution result

  • And then someone else said, when the last timethenMethod is a time-consuming and easy operation, will only output a value, such as:

  • Here follow the Promise source code provisions, in the Promise source code is stateful, there isthreeKind of state,Pending - Ongoing,Successfully fulfilled -,Rejected - failure. When the principal is finished executing, it changes the state and then executes it directly to add the followingthenMethod can be implemented, so the implementation, such as:
/ / state object const stateObj = {PENDING: 'PENDING', FULFILLED: 'FULFILLED, REJECTED: } class MyPromise {constructor(constructor) {// initialize state this.state = statej.pending // initialize value this.value = null; Callbacks = [] // bind this to const resolve = this.resolvie.bind (this) try {queueMicrotask(() => func(resolve))} This is very depressing. This is very depressing. This is very depressing. This is very depressing This.callbacks.foreach (cb => {let newValue = cb(this.value) // Store the value returned by the then method this.value = newValue})} reject() { console.error(stateObj.REJECTED) } then(cb) { if (this.state === stateObj.PENDING) { this.callbacks.push(cb) return this } try {// execute the incoming method cb(this.value)} catch (error) {this.reject()} return this}} const mp = new MyPromise((resolve, _) => resolve(2)).then(e => { console.log(e) return e * 2 }) setTimeout(() => { mp.then(e => { console.log(e) return e * 2})}, 3000)Copy the code
  • The execution results are back

Ok, today to play here, the follow-up continue to optimize