[19] handwritten promise

Time:2022-5-22

Navigation

[01] execution context
[02] prototype chain
[03] inheritance
[04] event loop
[05] Coriolis partial function memory
[06] implicit conversions and operators
[07] browser caching mechanism (HTTP caching mechanism)
[08] front end security
[deep 09] deep and shallow copy
[10] debounce throttle
[11] front end routing
[12] front end modularization
[13] observer mode publish subscribe mode bidirectional data binding
[14] canvas
[15] websocket
[16] webpack
[17] HTTP and HTTPS
[18] CSS interview
[19] handwritten promise
[20] handwriting function

[react] Hooks

[deployment 01] nginx
[02] docker deployment Vue project
[deployment 03] gitlab Ci

[source code webpack01 pre knowledge] ast abstract syntax tree
[source code webpack02 pre knowledge] tapable
[source code – webpack 03] handwritten webpack – compiler simple compilation process
[source code] Redux react-redux01
[source code] Axios
[source code] vuex
[source code – vue01] data responsive and initialization rendering
[source code – vue02] computed response – initialization, access, update process

Pre knowledge

Some words

Race: race, race
Settled: end

Execute: Execute
Executor: executor

Detected: detected

Promise review

  • method
    • promise. Then () ———————————- return a new promise
    • promise. Catch() ———————————- return a new promise
    • promise. Finally () —————— it will be executed regardless of the status
    • promise. All() ——————————- all resolved are fully satisfied, and one reject is rejected
    • promise. Any() ———————————- one resolve is fully satisfied, and all reject is rejected
    • promsie. Race() ————————————— the first resolve is full, and the first reject is rejected
  • characteristic
    • The state of the object is not affected by the outside world. Only the result of asynchronous operation can determine the current state. No other operation can change this state
    • Once the state changes, it will not change again. This result can be obtained at any time
  • <font color=red>shortcoming</font>
    • Promise cannot be cancelled. Once a new one is created, it will be executed immediately. It cannot be cancelled halfway
    • If the callback is not set, the error thrown internally will not be reflected externally
    • When it is in pending status, it is impossible to know which stage it is currently progressing to (just beginning? About to end?)
  • Promise usage
const promise = new Promise(function(resolve, reject) {
  // ... some code
  If (/ * asynchronous operation succeeded * /){
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});


explain:
(1) Promise constructor accepts a (function) as an argument
(2) (parameter function) accepts two functions as parameters (resolve function) and (reject function)
(3) resolve() 
    -The function is called when the state is pending - > fully, that is, when it is successful, and passes the result of the asynchronous operation as a parameter
    -The parameter of the resolve () function can be a promise instance in addition to a normal value
(4) reject() 
    -The function is called when the status is pending - > rejected, that is, when it fails, and passes the error reported by the asynchronous operation as a parameter
    -The parameter of reject() function is usually an instance of (error object)
(5) The then () method takes two functions as arguments
    -The first parameter function is called when resolve
    -The second parameter function is called when rejecting. The parameters are final value and rejection respectively. The second parameter function is optional
  • resolve()
    • The resolve () and reject () functions will not terminate promise, and the following code will still be executed
    • < font color = Red > the operation of promise constructor code is usually ended by return resolve() return reject() < / font >
    • <font color=blue>The parameter of the resolve () function is a promise instance</font>
let count = 1
setInterval(() => {console.log(count++)}, 1000)

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => {
    console. Log ('code in P1 starts executing ')
    reject(new Error('fail'))
  }, 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => {
    console. Log ('code in P2 starts executing ');
    resolve(p1)
  }, 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
  

analysis:
(1) The state of P2 changes to success after 1s. The parameter P1 of resolve (P1) is still a promise, resulting in the failure of the state of P2
(2) If the state of P2 fails, the state of P2 is determined by P1
(3) After 3S, the state of P1 changes to failure, reject (new error ('fail '), so after 3S, the state of P2 also changes to failure
(4) The failure status of P2 is determined by P2 Catch() capture
  • then()
    • < font color = Red > returns a new promise instance, so you can use chain writing < / font >
    • < font color = blue > if the then() method is called in a chain, the previous then() may return a promise instance, then the callback function of the latter then() needs to wait for the state of the previous then() to change before calling < / font >
  • catch()
    • The main function of < font = promise > is to capture a new error in the process of < / font = color > promise
    • The method of. Catch() is an object that returns. Color = blue Catch () can be called later then()</font>
    • Catch() yes.then(null, rejection)or.then(undefined, rejection)Alias for specifying what happenserrorTimelyCallback function
    • Any error thrown by then () in front of catch () and within promise can be caught by catch ()
    • be careful:
      • A callback only needs to be added after the successful state in then (), while the failed state is captured by catch ()
  • finally()
    • < font color = Red > the operation will be executed no matter what the final state of the promise object is < / font >
    • < font color = blue > the callback function of finally() does not accept any parameters, because the operation in the callback function of finally() has nothing to do with the state < / font >
  • all()
    • All resolve() will be fulfilled, and one reject() will be rejected
  • any()
    • One resolve() is fully satisfied, and all reject() are rejected
    • Contrary to all()
  • race()
    • One resolve () is full and one reject () is rejected
  • allSettled()
    • The wrapper instance will not end until all instances of parameters return results
    • For example, wait for all requests to complete, and end the loading animation regardless of success or failure

Handwritten promise

class Promise {
  constructor(executor) {
    //The parameter is not a function and an error is reported
    if (typeof executor !== 'function') {
      throw new TypeError(`Promise resolver ${executor} is not a function`)
    }
    this. Init() // initialization value
    try {
      executor(this.resolve, this.reject)
    } catch (err) {
      //Use try The purpose of catch is to throw the error in executor () to the callback of then to catch it
      this.reject(err)
    }
  }


  init = () => {
    this. Value = null // final value
    this. Reason = null // cause of rejection
    this. state = Promise. Pending // status

    this. Onfulfilledcallbacks = [] // successful callback. Execute when push and resolve() in then() method
    this. Onrejectedcallbacks = [] // failed callback, which is executed when pushing and rejecting () in then() method
  }

  resolve = (value) => {
    //A series of operations after success (change of state, execution of successful callback)
    //Status change: pending - > fulfilled

    // console.log(this.constructor === Promise) // true
    //This in the arrow function, the scope is bound in the parent execution context, that is, the object where it is defined
    //That is, this is equivalent to the parent's this. Here, it is in the tick function, so this points to the instance object 
    if (this.state === Promise.PENDING) {
      this.state = Promise.FULFILLED
      this.value = value

      this.onFulfilledCallbacks.forEach(fn => fn(this.value))
      //When there is an asynchronous operation in the parameter function of promise, the then method will execute first before resolve () or reject ()
      //This causes the state to be pending when the then () method is executed, because the change of state is changed in resolve () or reject (), and they are not executed because of asynchrony
      //This is an array that needs to be used to store the onfulfilled function that will be executed in the future
      //Here, the function of onfulfilledcallbacks is pushed, which will be executed in the resolve () function
    }
  }

  reject = (reason) => {
    //A series of operations after failure (change of state, execution of failed callback)
    //Status change: pending - > rejected
    if (this.state === Promise.PENDING) {
      this.state = Promise.REJECTED
      this.reason = reason

      this.onRejectedCallbacks.forEach(fn => fn(this.reason))
    }
  }

  then = (onFulfilled, onRejected) => {
    //Parameter verification, penetration effect, that is, then has penetration effect without transmitting any parameters
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }
    //Parameter verification, penetration effect, that is, then has penetration effect without transmitting any parameters
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }

    //The then () method returns a new instance of promse
    //Because the new promise instance is returned, the chain call can be realized
    let promise2 = new Promise((resolve2, reject2) => {
      //Condition for executing onfulfilled function
      if (this.state === Promise.FULFILLED) {
        setTimeout(() => {
          //Here, the callback onfulfilled () function in the then () method in the middle has a return value
          //The return value of the intermediate then () parameter function onfulfilled () will be passed in as the parameter of the next then callback
          try {
            const x = onFulfilled(this.value)
            Promise.resolvePromise(promise2, x, resolve2, reject2)
          } catch (err) {
            reject2(err)
          }

        })
      }
      if (this.state === Promise.REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason)
            Promise.resolvePromise(promise2, x, resolve2, reject2)
          } catch (err) {
            reject2(err)
          }

        })
      }
      if (this.state === Promise.PENDING) {
        //If the status is pending
        //When there is an asynchronous operation in the parameter function of promise, the then method will execute first before resolve () or reject ()
        //This causes the state to be pending when the then () method is executed, because the change of state is changed in resolve () or reject (), and they are not executed because of asynchrony
        //In this case, you need to use an array to store the onfulfilled function that will be executed in the future
        //Here, the function of onfulfilledcallbacks is pushed, which will be executed in the resolve () function
        this.onFulfilledCallbacks.push((value) => {
          //You still need to use setTimeout here, because this function is executed in resolve (). If any code is synchronized after resolve (), ensure that the synchronization code is executed first
          setTimeout(() => {
            try {
              const x = onFulfilled(value)
              Promise.resolvePromise(promise2, x, resolve2, reject2)
            } catch (err) {
              reject2(err)
            }
          })
        })
        this.onRejectedCallbacks.push((reason) => {
          setTimeout(() => {
            try {
              const x = onRejected(reason)
              Promise.resolvePromise(promise2, x, resolve2, reject2)
            } catch (err) {
              reject2(err)
            }

          })
        })
      }
    })
    return promise2
  }
}

//Static attributes are used here to avoid magic strings
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
Promise.resolvePromise = function (promise2, x, resolve, reject) {
  //X is equal to PROMISE2
  if (promise2 === x) {
    reject(new TypeError('chainning cycle detected for promise'))
  }
  //X is promise
  if ( x instanceof Promise) {
    x.then(value => {
      // resolve(value)
      Promise.resolvePromise(promise2, value, resolve, reject)
    }, reason => {
      reject(reason)
    })
  } 
  else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    //X is an object or function
    try {
      const then = x.then
      if (typeof then === 'function') {
        then.call(
          x,
          value => {
            if (called) return
            called = true
            MyPromise.resolvePromise(promise2, value, resolve, reject)
          },
          reason => {
            if (called) return
            called = true
            reject(reason)
          }
        )
      } else {
        if (called) return
        called = true
        resolve(x)
      }
    } catch (e) {
      if (called) return
      called = true
      reject(e)
    }
  } else {
    resolve(x)
  }
}


const promise = new Promise((resolve, reject) => {
  //Throw new error ('error ')
  console.log(1)
  setTimeout(() => {
    console.log(4)
    resolve(6)
    console.log(5)
  })
  console.log(2)
})
  .then(
    value => {
      console.log(value, 'value')
      return new Promise(resolve => {
        resolve(new Promise(resolve3 => {
          resolve3(7)
        }))
      })
    },
    reason => {
      console.log(reason, 'reason')
    })
  .then(
    value => {
      console.log(value, 'vvvvvvvvvvvv')
    }, reason => {
      console.log(reason)
    })
console.log(3)



// then
  //The two parameter callback functions in then need to be asynchronous, which is solved by setTimeout
  //If an error is thrown inside the promise parameter function, you need to catch = > try in then() catch
  //If there is asynchrony in promise, then's callback will not be executed = > because when executing the then method, state = = = 'pending' does not meet the need to execute either of then's two callbacks, and when resolve() in setTimeout is executed, then will not continue to execute

The parameter of new promise() must be a function. If it is not a function, an error will be reported

Native:
new Promise(1)
TypeError: Promise resolver 1 is not a function


Simulation Implementation:
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      //The parameter must be a function, not an error thrown by the function
      throw new TypeError(`Promise resolver ${executor} is not a function`)
    }
    executor(this.resolve, this.reject)
  }
}
const promise = new Promise()
// TypeError: Promise resolver undefined is not a function

The main role of the resolve () method

  • (1) Change the status (< font color = Red > status < / font >) from (< font color = Red > pending – > fully < / font >)
  • (2) Assign the final value (< font color = Red > value < / font >) to the (< font color = Red > parameter < / font >) passed in by the resolve() function
  • (3) Take out the functions in (< font color = Red > onfulledcallback array < / font >) and execute accordingly
    • If there is an asynchronous operation in promise, then () executes before resolve ()
    • Therefore, in the then () method, you need to push a function into the onfulledcallback array that will be executed in resolve () in the future

The main role of the rejected () method

  • (1) Change the status (< font color = Red > status < / font >) from (< font color = Red > pending – > rejected < / font >)
  • (2) Assign the rejection factor (< font color = Red > value < / font >) to the (< font color = Red > parameter < / font >) passed in by the reject() function
  • (3) Take out the functions in (< font color = Red > onrejectedcallback array < / font >) and execute accordingly
    • If there is an asynchronous operation in promise, then () executes before resolve ()
    • Therefore, in the then () method, you need to push a function into the onfulledcallback array that will be executed in reject () in the future
class Promise {
  constructor(executor) {
    if (typeof executor !== 'function') {
      //The parameter must be a function, not an error thrown by the function
      throw new TypeError(`Promise resolver ${executor} is not a function`)
    }
    this.init()
    executor(this.resolve, this.reject)
  }
  init = () => {
    this. Value = null // final value, initialization
    this. Reason = null // cause rejection, initialization
    this. status = Promise. Pending // status, pending during initialization
    this. Onfulfilledcallbacks = [] // successful callback. Execute when push and resolve() in then() method
    this. Onrejectedcallbacks = [] // failed callback, which is executed when pushing and rejecting () in then() method
  }
  resolve = (value) => {
    if (this.status === Promise.PENDING) {
      this.status = Promise.FULFILLED
      this.value = value
      this.onFulfilledCallbacks.forEach(fn => fn(value))
    }
  }
  reject = (reason) => {
    if (this.status === Promise.PENDING) {
      this.status === Promise.REJECTED
      this.reason = reason
      this.onRejectedCallbacks.forEach(fn => fn(resaon))
    }
  }
  then = (onFulfilled, onRejected) => {
    if (this.status === Promise.FULFILLED) {
      onFulfilled(this.value)
    }
    if (this.status === Promise.REJECTED) {
      onRejected(this.reason)
    }
    if (this.status === Promise.PENDING) {
      this.onFulfilledCallbacks.push((value) => onFulfilled(value))
      this.onRejectedCallbacks.push((reason) => onRejected(reason))
    }
  }
}

Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  })
}).then(value => {
  console.log(value)
}, reason => {
  console.log(reason)
})

When the then () method does not pass parameters

  • You need to override the onfulfilled function to return the current final value this value
  • The onrejected function needs to be rewritten to return the current rejection this Reason and throw
then = (onFulfilled, onRejected) => {
        if (typeof onFulfilled !== this.FUNCTION) {
            //Rewrite the function without passing the onfulfilled parameter
            //Return the call parameters as they are
            //There is no direct writing (typeof onfulfilled! = = 'function') to prevent magic strings
            onFulfilled = value => value 
        }
        if (typeof onRejected !== this.FUNCTION) {
             //Rewrite the function without passing the onrejected parameter
             //Throw reason
            onRejected = reason => {
                throw reason
            }
        }
        if (this.status === this.FULFILLED) {
            //The onfulfilled function is executed only when the status is full, and the parameter is the current final value
            //That is, the callback function added when the status changes to success
            //Here, both passed parameters and no passed parameters will be executed. No passed parameters are onfulfilled after being rewritten
            onFulfilled(this.value)
        }
        if (this.status === this.REJECTED) {
            onRejected(this.reason)
        }
    }

Then () guarantees execution order 1

  • < font color = Red > then() the callback function in then() can execute < / font > only after the synchronization code is executed
console.log(1)
const promise = new Promise((resolve, reject) => {
  console.log(2)
  resolve(5)
  console.log(3)
})
.then(value => {
  console.log(value)
}, reason => {
  console.log(reason)
})
console.log(4)


Question: how to ensure that the execution order is 12345
Solution: then () is an asynchronous method, that is, the parameter callback of then () method needs to be executed after the resolve () or reject () method is executed. Use (timer) to solve it
Note: if the timer is not used, the execution sequence is 


then = (onFulfilled, onRejected) => {
    if (typeof onFulfilled !== Promise.FUNCTION) {
      onFulfilled = value => value
    }
    if (typeof onRejected !== Promise.FUNCTION) {
      onRejected = reason => reason
    }
    if (this.status === Promise.FULFILLED) {
      SetTimeout (() = > {// use setTimeout () to simulate the asynchronous execution of onfulfilled. Ensure that the onfulfilled code is executed after the synchronous code is executed
        onFulfilled(this.value)
      })
    }
    if (this.status === Promise.REJECTED) {
      SetTimeout (() = > {// use setTimeout () to simulate the asynchronous execution of onrejected. Ensure that onrejected is executed after the synchronous code is executed
        onRejected(this.reason)
      })
    }
    if (this.status === Promise.PENDING) {
      this.onFulfilledCallbacks.push((value) => onFulfilled(value))
      this.onRejectedCallbacks.push((reason) => onRejected(reason))
    }
  }

Then () guarantees execution sequence 2

  • < font color = Red > when there is asynchronous code in promise, the then() method will execute before resolve(), and the status =’pending ‘status is < / font >
  • < font color = Red > when the relevant operation when the status is pending is not added in the then method, neither of the two callbacks in then () will execute < / font >
console.log(1)
new Promise((resolve, reject) => {
    console.log(2)
    setTimeout(() => resolve())
   //When there is asynchronous operation here, the above code prints only 123. Note that 4 is not printed
   //The reason is that the then () method is executed before the resolve () method. Because resolve is asynchronous, the state in then () is still pending
   //In the then method, the related operations when the adding state is the pending state
}).then(() =>  console.log(4))
console.log(3)



Problem: 123 is printed, but 4 is not printed
analysis:
  1. The reason is that the then () method is executed before the resolve () method. Because resolve is asynchronous, the state in then () is still pending
  2. In the then method and when the adding state is the pending state
solve:
  1. Add relevant judgment in pending state in then () method
      -And push a party method into the onfulfilled callbacks array. Call the onfulfilled method from this party. The parameter is the current value
      -And push a method into the onrejectedcallbacks array. Call the onrejected method from this side. The parameter is the current reason
  2. In the resolve () method, loop the onfulledcallbacks array and execute the function inside. The argument is this value
  2. In the reject () method, loop the onrejectedcallbacks array and execute the function inside. The argument is this reason



then = (onFulfilled, onRejected) => {
        ...
        if (this.status === this.PENDING) {
            //Pending status push function to onfulledcallbacks array
            this.onFulfilledCallbacks.push(value => onFulfilled(value)) 
            this.onRejectedCallbacks.push(reason => onRejected(reason))
        }
    }
 resolve = (value) => {
        if (this.status === this.PENDING) {
            this.status = this.FULFILLED
            this.value = value
            this. onFulfilledCallbacks. Foreach (FN = > FN (this. Value)) // execute the functions in the array and pass in the arguments
        }
    }
reject = (reason) => {
        if (this.status === this.PENDING) {
            this.status = this.REJECTED
            this.reason = reason
            this.onRejectedCallbacks.forEach(fn => fn(this.reason))
        }
    }

Then () guarantees execution sequence 3

console.log(1)
new Promise((resolve, reject) => {
    console.log(2)
    setTimeout(() => {
        resolve()
        console. Log (4) // ensure that 4 is executed before 5, because 4 is the synchronization code
    })
}).then(() =>  console.log(5))
console.log(3)



Problem: the above code outputs 12354, while the real promise should output 12345
Analysis: because there is synchronization code after resolve (), ensure that the following synchronization code is executed first
Solution: when pushing the method into the onfulledcallbacks array, wrap it with setTimeout and let the code after resolve () execute first



    then = (onFulfilled, onRejected) => {
       ...
        if (this.status === this.PENDING) {
            this.onFulfilledCallbacks.push(value => {
                The callback (= >) of the function setTimeout () is used to ensure that the callback (= >) after the function setTimeout () is executed first
                    onFulfilled(value)
                }, 0)
            })
            this.onRejectedCallbacks.push(reason => {
                setTimeout(() => {
                    onRejected(reason)
                }, 0)
            })
        }
    }

Chained call to then()

  • The < font color = Red > then() method returns a new promise instance. Note that it is not the original, so you can call < / font >
  • < font color = Red > in the new promise, the resolve of the parameter function is the value returned after the onfufiled function is executed < / font >
then = (onFulfilled, onRejected) => {
    //Parameter verification, penetration effect, that is, then has penetration effect without transmitting any parameters
    if (typeof onFulfilled !== Promise.FUNCTION) {
      onFulfilled = value => value
    }
    //Parameter verification, penetration effect, that is, then has penetration effect without transmitting any parameters
    if (typeof onRejected !== Promise.FUNCTION) {
      onRejected = reason => reason
    }
    const promise2 = new Promise((resolve2, reject2) => {
      if (this.status === Promise.FULFILLED) {
        setTimeout(() => {
          const x = onFulfilled(this.value)
          //Pass the return value of onfulfilled function as the parameter of resolve() to the new then() method
          resolve2(x)
        })
      }
      if (this.status === Promise.REJECTED) {
        setTimeout(() => {
          const x = onRejected(this.reason)
          reject2(x)
        })
      }
      if (this.status === Promise.PENDING) {
        this.onFulfilledCallbacks.push((value) => {
          setTimeout(() => {
            const x = onFulfilled(value)
            resolve2(x)
          })
        })
        this.onRejectedCallbacks.push((reason) => {
          setTimeout(() => {
            const x = onRejected(reason)
            reject2(x)
          })
        })
      }
    })
    return promise2
  }
More detailed

then = (onFulfilled, onRejected) => {
        if(typeof onFulfilled !== 'function') {
          onFulfilled = (value) => value
        }
        if(typeof onRejected !== 'function') {
          onRejected = (reason) => {
            throw reason
          }
        }
        const promise2 = new Promise((resolve, reject) => {
          if (this.status === Promise.FULFILLED) {
            setTimeout(() => {
              try {
                Const x = onfulfilled (this. Value) // pass the return value of onfulfilled function as the parameter of resolve() to the new then() method
                Resolve (x) // promise 2's resolve timing
              } catch(err) {
                Reject (ERR) // the timing of the reject of PROMISE2
              }
            })
          }
          if (this.status === Promise.REJECTED) {
            setTimeout(() => {
              try {
                const x = onRejected(this.reason)
                resolve(x)
              } catch (err) {
                reject(err)
              }
            })
          }
          if (this.status === Promise.PENDING) {
            this.onFulfilledCallbacks.push((value) => {
              setTimeout(() => {
                try {
                  const x = onFulfilled(value)
                  resolve(x)
                } catch(err) {
                  reject(err)
                }
              })
            })

            this.onRejectedCallbacks.push((reason) => {
              setTimeout(() => {
                try {
                  const x = onRejected(reason)
                  resolve(x)
                } catch(err) {
                  reject(err)
                }
              })
            })
          }
        })

        return promise2
      }

Promise. All() Simulation Implementation

  • p = Promsie.all([p1, p2, p3])
  • Return value: promise All() returns a new promise instance
  • Parameters:
    • (< font color = Red > parameter < / font >) is a (< font color = Red > array < / font >) or data with (< font color = Red > iterator < / font >) interface type, and the members are promsie instances
    • If it is not a promsie instance, it will call promsie Resolve() to promsie instance
  • effect:
    • If the state of all parameter array members becomes full, the whole state becomes full
      • At this time, the return values of resolve () in P1, P2 and P3 will form an array and be passed to the callback function of P
    • If the state of one parameter array member becomes rejected, the whole state becomes rejected
      • At this point, the return value of the first rejected reject () will be passed to the callback function of P
explain:
1. Promise. All () returns a new promise, that is, you can use then to get the results of resolve and reject
2. The parameter is an array or data with iterator interface
3. If the parameter array member is not promise, it will be promised Resolve() to promise object
4. The time to resolve is when all parameter members become fully qualified
5. The time to reject is when there is only one rejected status


Promise.all = (promises) => {
    //Returns a new promise instance
    return new Promise((resolve, reject) => {
        const arr = []
        Let count = 0 // record the number of promises in the full status
        const promiseArr = Array. From (promises) // in addition to array, the parameter can also be a data type with iterator interface
        const len = promiseArr.length
        for (let i = 0; i < len; i++) {
            Promise. resolve(promiseArr[i]). Then (value = > {// if the parameter is not promise, promise. Resolve() will be called to turn it into promise
                Count + + // entering here indicates a successful callback, i.e. the status of completed
                Arr [i] = value // load the successful promise into the array
                if (count === len) { 
                    console.log(count, 'count')
                    resolve(arr)
                    //If the count and the total length of the array are equal, it indicates that they are in the fully completed state
                    //The opportunity for all to resolve is for all to become fully resolved
                }
            }, reject) // what is written here is not perfect. Please see the latest supplement below
        }
    })
}

const a = Promise.resolve(1)
const b = Promise.resolve(2)
const c = new Promise(resolve => {
    setTimeout(() => {
        resolve(33)
    })
})

Promise.all([a, b, c]).then(value => console.log(value, 'value'))

Promise was modified on April 7, 2021 All simulation implementation

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    //Handwritten promise all
    // 1.  Promise. All returns a new promise
    // 2.  Promise. The parameter of all is an array, and the member is promise object. If it is not promise object, the parameter will be converted to promise first
    // 3.  If all members are full, the whole state becomes full
    // 4.  If one is rejected, the whole state becomes rejected

    const promise1 = Promise.resolve(1)
    const promise2 = Promise.resolve(2)
    const promise3 = Promise.resolve(3)
    const promise4 = Promise. Reject (new error ')

    Promise.all2 = (promises) => {
      Return new promise ((resolve, reject) = > {// promise. All() returns a new promise object
        const promisesArr = Array.from(promises)
        const len = promisesArr.length

        let count = 0
        const results = []

        for (let i = 0; i < len; i++) {
          Promise. resolve(promisesArr[i]). Then (value = > {// if the parameter is not promise, turn it to promise first
            count++
            results.push(value)
            if (results.length === len) {
              Resolve (results) // resolve (results) the entire final value array when no error occurs after traversing the array
            }
          }, reason = > reject (reason)) // as long as one error occurs, the rejection of the whole reject occurs first
        }
      })
    }

    Promise.all2([promise1, promise2, promise3]) // fulfilled
      .then(value => console.log(value))
      .catch(err => console.log(err))

    Promise.all2([promise1, promise2, promise3, promise4]) // rejected
      .then(value => console.log(value))
      .catch(err => console.log(err))
  </script>
</body>
</html>

Proimse. Race () simulation implementation

Promise.race = (promises) => {
      return new Promise((resolve, reject) => {
        const promiseArr = Array.from(promises)
        const len = promises.length

        for(let i = 0; i < len; i++) {
          Promise.resolve(promiseArr[i]).then(value => {
            Resolve (value) // directly resolve. The first then is the final value received by the callback function when it succeeds
          })
        }
      })
    }

Summarize some interview questions encountered 2021 / 04 / 10

(1) Promise interview question 1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    console.log(1)
    SetTimeout (() = > {// timer a
      console.log(2);
      Promise.resolve().then(() => { // Promise D
        console.log(3)
      })
    })
    new Promise((resolve, reject) => { // Promise B
      console.log(4)
      resolve(5)
    }).then((data) => {
      console.log(data)
    })
    SetTimeout (() = > {// timer C
      console.log(6)
    })
    console.log(7)
/****
         Answer: 1 4 7 5 2 3 6
    
         analysis:
         1. First event cycle
         Synchronization task: 1
         Macro task: [a, C]
         Micro task: [b]
         Output: 1 4 7
    
         2. Second event cycle
         Traverse all micro tasks [b] = > 5
         Take out the first macro task [a] = > 2, and add micro task d to the task queue. At this time, micro task queue [D]
         Output: 5 2
    
         3. The third event cycle
         Traverse all micro tasks [D] = > 3
         Take out the first red task [C] - > 6
         Output: 3 6
*/
  </script>
</body>
</html>

(2) Promise interview question 2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    console.log(1)
    // A promise
    new Promise((resolve) => {
      console.log(2)
      resolve()
      console.log(3)
    }).then(res => { // E then
      console.log(4)
      //C timer
      setTimeout(() => console.log(5))
    })
    console.log(6)
    //B timer
    setTimeout(() => {
      console.log(7)
      // D promise
      new Promise((resolve) => {
        console.log(8)
        resolve()
      }).then(() => console.log(9)) // F then
    })
    console.log(10)
    /**
     *First round event loop
     *1 = > synchronize the task, enter the function call stack and execute it immediately
     *A = > the callback of a is executed immediately
     *2 = > synchronization task, execute immediately
     *E = > micro task, enter the micro task queue
     *3 = > synchronization task, execute immediately
     *6 = > synchronization task, execute immediately
     *B = > macro task, and the callback of B enters the macro task queue
     *10 = > synchronization task, execute immediately
     *At this time, the implementation is as follows:
     *Output: 1, 2, 3, 6, 10
     *Micro task: [e]
     *Macro task: [b]
     *
     *Second round event loop
     *Empty the micro task queue and take out the first member of the macro task queue
     *E = > 4 synchronization tasks, execute immediately
     *C macro task, enter the macro task queue, and the macro task queue at this time [b, C]
     *B = > 7 synchronization tasks, execute immediately
     *The callback of d promise is executed immediately
     *= > 8 synchronization task, execute immediately
     *= > F micro task, enter the micro task queue, and the micro task queue at this time [F]
     *At this time, the implementation is as follows:
     *Output: 4, 7, 8
     *Micro task: [F]
     *Macro task: [C]
     *
     *The third round of event loop
     *Empty the micro task queue and take out the first member of the macro task queue
     *F = > 9 synchronization task, execute immediately
     *C = > 5 synchronization tasks, execute immediately
     *
     *Total output sequence: 1, 2, 3, 6, 10, 4, 7, 8, 9, 5
     */
  </script>
</body>
</html>

data

Handwritten promisehttps://segmentfault.com/a/1190000012820865
Handwritten promisehttps://juejin.im/post/6844903872842956814