Last time we analyzed multiple THEN calls

If you haven’t read an article yet, read half of it and write a promise to end it by hand.

In fact, the last time I noticed that I was always using setTimeout for callbacks, and when I took setTimeout out, it was nothing. Split. Still have to come back to find the problem, ┭┮﹏┭┮

        then (successCallback, failCallback) {
          if (this['[[PromiseState]]'= = ='fulfilled') {
            successCallback && successCallback(this['[[PromiseResult]]'])}else if (this['[[PromiseState]]'= = ='rejected') {
            failCallback && failCallback(this['[[PromiseResult]]'])}else if (this['[[PromiseState]]'= = ='pending') {
            this.resolveFn.push(successCallback)
            this.rejectFn.push(failCallback)
          }
        }
      }
      const myP = new myPromise((resolve, reject) = > {
        reject('err')
      })
      myP.then(res= > {
        console.log('res', res)
      }, err= > {
        console.log('err', err)
      })
Copy the code

I modified then to determine whether to execute immediately or store it based on its state. SetTimeout (() => {run()}) => {run()}

┭┮﹏┭┮ is too difficult, I write so much if judgment fuck, is not the result I want

      // 222 -- 333-555 -- 444 -- 111 Expected result
      setTimeout (() = > {
        console.log('1111')},2000)
      console.log('222')
      const myP = new myPromise((resolve, reject) = > {
        console.log('333')
        resolve('suss')
      })
      myP.then(res= > {
        console.log('444')
        console.log('res', res)
      }, err= > {
        console.log('err', err)
      })
      console.log('5555')
      console.log('myP', myP)
Copy the code

This is what it turns out to be. Why, crack.

As you can see from the above, my promise doesn’t have micro or macro tasks that are synchronous

Since I didn’t set a micro or macro task between Promise Resolve and then, I still need to setTimeout( () => { run() })“, but it would be more accurate to write microtasks

          const observer = new MutationObserver(run)
          observer.observe(document.body, {
            attributes: true
          })
          document.body.setAttribute('what'.'shenmewanyier')
Copy the code

That’s the end of this little episode. Here we go

6. Chain call. Normally the key to a chained call is return this but if you return a return this it’s going to happen every time there’s no connection between the chain, it’s always going to return an instance of something new, so you’re going to return a new promise every time, okay

        then (successCallback, failCallback) {
          return new myPromise ((resolve, reject) = > {
            let resolveFn = (res) = > {
              let val = successCallback && successCallback(res) // Get the result of the callback function
              resolve(val)
            }
            this.resolveFn.push(resolveFn)

            let rejectFn = (res) = > {
              let val = failCallback && failCallback(res)
              reject(val)
            }
            this.rejectFn.push(rejectFn)
          })
        }
        
      const myP = new myPromise((resolve, reject) = > {
        resolve('suss')
      })
      myP.then(res= > {
        console.log('res', res)
        return 'fhfh'
      }).then(res= > {
        console.log('122', res)
      })
Copy the code

So now we can only handle the case where we return a normal value, and we can return a promise. To pick up promise. Then returns the same value

        then (successCallback, failCallback) {
          return new myPromise ((resolve, reject) = > {
            let resolveFn = (res) = > {
              let val = successCallback && successCallback(res) // Get the result of the callback function
              // Determine the type of val
              if (val instanceof myPromise) {
                // val.then(a => {
                // resolve(a)
                // })
                val.then(resolve)
              } else {
                resolve(val)
              }
            }
            this.resolveFn.push(resolveFn)

            let rejectFn = (res) = > {
              let val = failCallback && failCallback(res)
              reject(val)
            }
            this.rejectFn.push(rejectFn)
          })
        }
Copy the code

Then finally ended. This stuff is so hard. Come on and keep going

Catch and finally are prototype methods, and Race, All, allSettled, resolve and reject are static methods

catch

Now let’s talk about catch, which we already implemented in then, so we can just call then again in the catch method

        catch (fn) {
          return this.then(undefined, fn)
        }
Copy the code

resolve

So let’s just print and see what will be returned after resolve


      const p = Promise.resolve('success')
      console.log(p)
Copy the code

It’s actually a promise object, so we’ll just return a promise

Note: Resolve is a static method

        static resolve (val) {
          return new myPromise (resolve= > {
            resolve(val)
          })
        }
Copy the code

reject

Reject is the same as resolve. Go to code!

        static reject (err) {
          return new myPromise ((resolve, reject) = > {
            reject(err)
          })
        }
Copy the code

race

A race is an array that terminates by taking the fastest possible result

        static race (list) {
          return new myPromise((resolve, reject) = > {
            list.forEach(element= > {
              item.then(res= > { // The one who is the fastest takes the first call
                resolve(res)
              }, err= >{ reject(err) }) }); })}Copy the code

allSettled

The difference between allSettled and All is that allSettled will collect whether settled succeeds or fails, while All will only collect successful results

Take a look at allSettled as it was


      const p = new Promise((resolve, reject) = > {
        setTimeout(() = > {
          resolve('111')},1000)})const p2 = new Promise((resolve, reject) = > {
          reject('222')})const p3 = new Promise((resolve, reject) = > {
          resolve('333')})Promise.allSettled([p, p2, p3]).then(res= > {
        console.log('allSettled', res)
      }, err= > {
        console.log('allSettled err', err)
      })
      console.log(p)
Copy the code

So what it looks like is an array with each object corresponding to a result set, including status, Success: value, and failure: Reason. So let’s get started

        static allSettled (lists) {
          let resArr = new Array(lists.length) // Lists result sets must correspond one to one and be of equal length
          let num = 0 // Lists complete
          return new myPromise( resolve= > {
            lists.forEach((item, key) = > {
              let obj = {}
              item.then(res= > {
                obj['status'] = 'fulfilled'
                obj['value'] = res
                resArr[key] = obj
                num++
                if (num >= lists.length) {
                  resolve(resArr)
                }
              }, err= > {
              obj['status'] = 'rejected'
              obj['reason'] = err
              resArr[key] = obj
              num++
              if (num >= lists.length) {
                  resolve(resArr)
              }
            })
            })
          })
         }
Copy the code
      const myP = new myPromise((resolve, reject) = > {
        setTimeout(() = > {
          resolve('111')},1000)})const myP2 = new myPromise((resolve, reject) = > {
        reject('222')})const myP3 = new myPromise((resolve, reject) = > {
        resolve('332')
      })
      myPromise.allSettled([myP, myP2, myP3]).then(res= > {
        console.log('results', res)
      })
Copy the code

AllSettled, just two more, finally, all, resids

all

All is reject, reject, reject, reject, reject, reject, reject, reject, reject, reject, reject

      const p = new Promise((resolve, reject) = > {
        setTimeout(() = > {
          resolve('111')},1000)})const p2 = new Promise((resolve, reject) = > {
          resolve('222')})const p3 = new Promise((resolve, reject) = > {
          resolve('333')})Promise.all([p, p2, p3]).then(res= > {
        console.log('allSettled', res)
      }, err= > {
        console.log('err', err)
      })
Copy the code

Do it!!

        static all (list) {
          let successArr = new Array(list.length) // Successful result set
          let flag = false // Whether there is an error message
          const length  = list.length
          return new myPromise((resolve, reject) = > {
            for (let i = 0; i < length; i++ ) {
              list[i].then(res= > {
                successArr[i] = res
                if (i >= list.length -1 && !flag) {
                  resolve(successArr)
                }
              }, err= > {
                flag = true
                reject(err)
                return})}})}Copy the code

The result was correct but flawed…

Why does this print out a blank, although it does not affect, but I am a pursuit of perfection, how can this. Me!!!!!!!! No!!!!! Done!!!!! Xu!!!!!

You can always trust the Debugger, but you can’t always trust console.logThis article explains my little question

After resting for a few hours, open the code again, run, and everything is fine?? ε=(´ο ‘*)))

finally

Last one!! Finally means that either resolve or reject is executed and no argument is returned. That’s not search done!!

        finally (Callback) {
          if (this['[[PromiseState]]']! = ='pending') {
            Callback && Callback()
          }
        }
Copy the code

It’s finally over! Finally, the complete code is attached

class myPromise {
        constructor (handle) {
          this['[[PromiseState]]'] = 'pending'
          this['[[PromiseResult]]'] = undefined
          this.resolveFn = []
          this.rejectFn = []
          handle(this.#resolve.bind(this), this.#reject.bind(this)) //
        }
        /** * I use resolve and reject as internal functions */ for maintenance purposes
        #resolve (val) {
          this['[[PromiseState]]'] = 'fulfilled'
          this['[[PromiseResult]]'] = val
          // this.resolveFn && this.resolveFn(val)
          // Push in from the back and pull out from the top
          const run = () = > {
            let cb
            while (cb = this.resolveFn.shift()) {
              cb && cb(val)
            }
          }
          const observer = new MutationObserver(run)
          observer.observe(document.body, {
            attributes: true
          })
          document.body.setAttribute('what'.'shenmewanyier')
        }
        #reject (err) {
          this['[[PromiseState]]'] = 'rejected'
          this['[[PromiseResult]]'] = err
          // this.rejectFn && this.rejectFn(err)
          // Push in from the back and pull out from the top
          const run = () = > {
            let cb
            while (cb = this.rejectFn.shift()) {
              cb && cb(err)
            }
          }
          const observer = new MutationObserver(run)
          observer.observe(document.body, {
            attributes: true
          })
          document.body.setAttribute('what'.'shenmewanyier')
        }
        then (successCallback, failCallback) {
          return new myPromise ((resolve, reject) = > {
            let resolveFn = (res) = > {
              let val = successCallback && successCallback(res) // Get the result of the callback function
              // Determine the type of val
              if (val instanceof myPromise) {
                // val.then(a => {
                // resolve(a)
                // })
                val.then(resolve)
              } else {
                resolve(val)
              }
            }
            this.resolveFn.push(resolveFn)

            let rejectFn = (res) = > {
              let val = failCallback && failCallback(res)
              reject(val)
            }
            this.rejectFn.push(rejectFn)
          })
        }
        catch (fn) {
          return this.then(undefined, fn)
        }
        finally (Callback) {
          if (this['[[PromiseState]]']! = ='pending') {
            Callback && Callback()
          }
        }

        static all (list) {
          let successArr = new Array(list.length) // Successful result set
          let flag = false // Whether there is an error message
          const length  = list.length
          return new myPromise((resolve, reject) = > {
            for (let i = 0; i < length; i++ ) {
              list[i].then(res= > {
                successArr[i] = res
                if (i >= list.length -1 && !flag) {
                  resolve(successArr)
                }
              }, err= > {
                flag = true
                reject(err)
                return})}})}This is a big pity. /** * allSettled * Until all promises are settled, which is a big pity or rejected. Return a promise that completes after all promises have completed. With an array of objects, each corresponding to the result of each promise. * /
        static allSettled (lists) {
          let resArr = new Array(lists.length) // Lists result sets must correspond one to one and be of equal length
          let num = 0 // Lists complete
          return new myPromise(resolve= > {
            lists.forEach((item, key) = > {
              let obj = {}
              item.then(res= > {
                obj['status'] = 'fulfilled'
                obj['value'] = res
                resArr[key] = obj
                num++
                if (num >= lists.length) {
                  resolve(resArr)
                }
              }, err= > {
              obj['status'] = 'rejected'
              obj['reason'] = err
              resArr[key] = obj
              num++
              if (num >= lists.length) {
                  resolve(resArr)
              }
            })
            })
          })
         }
        static race (list) {
          return new myPromise((resolve, reject) = > {
            list.forEach(element= > {
              element.then(res= > { // The one who is the fastest takes the first call
                resolve(res)
              }, err= >{ reject(err) }) }); })}static reject (err) {
          return new myPromise ((resolve, reject) = > {
            reject(err)
          })
        }
        static resolve (val) {
          return new myPromise (resolve= > {
            resolve(val)
          })
        }
      }
      const myP = new myPromise((resolve, reject) = > {
        setTimeout(() = > {
          resolve('111')},3000)
      })
      myP.finally(() = > {
        console.log('the end')})const myP2 = new myPromise((resolve, reject) = > {
        resolve('222')})const myP3 = new myPromise((resolve, reject) = > {
        resolve('332')})Copy the code

Feel also broad to remember to point a praise, encourage me to write the article so carefully for the first time the small heart ^_^