1, the preface

In this article, by default, you already know what promises are, and I’ll walk you through a simple Promise implementation step by step. It will be done step by step in a gradual way.

This article related code address: github.com/layouwen/bl…

If this article has helped you, please don’t be stingy with your Start

2. Three states

Here’s the code, click here

Promise has three states:

  1. pending
  2. fulfilled
  3. rejected

Let’s implement our own class, which defaults to pending and changes its state by calling resolve or Reject

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
  }
  #reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
  }
}
console.log(new LPromise((resolve, reject) = > console.log('pending'))) / / pending state
const l1 = new LPromise((resolve, reject) = > {
  resolve('I called resolve')})console.log(l1) / / fulfilled state
const l2 = new LPromise((resolve, reject) = > {
  reject('I'm calling reject')})console.log(l2) / / rejected state
Copy the code

3, then parameter callback

Here’s the code, click here

Returns a Promise that can pass successful and failed callbacks by using then.

Two callbacks are received through THEN. Implements the content of calling the callback separately. But it turns out, they both do it.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
  }
  #reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
  }
  /* new content start */
  then(onResolve, onReject) {
    onResolve()
    onReject()
  }
  /* new content end */
}
const l1 = new LPromise((resolve, reject) = > resolve())
l1.then(
  res= > console.log('res'),
  err= > console.log('err'))Copy the code

Adjust the timing of execution. Make it execute the associated callback only when it calls resolve or Reject

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    /* new content start */
    this.cbResolve() / / an error
    /* new content end */
  }
  #reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    /* new content start */
    this.cbReject() / / an error
    /* new content end */
  }
  then(onResolve, onReject) {
    /* new content start */
    this.cbResolve = onResolve
    this.cbReject = onReject
    /* new content end */}}const l1 = new LPromise((resolve, reject) = > resolve())
l1.then(
  res= > console.log('res'),
  err= > console.log('err'))Copy the code

After modification, resolve and Reject were found to execute faster than callbacks for THEN. The callback in THEN cannot be executed. We need to defer the parts of resolve and Reject that perform callbacks. You can use setTimeout to delay

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    /* new content start */
    setTimeout(() = > this.cbResolve())
    /* new content end */
  }
  #reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    /* new content start */
    setTimeout(() = > this.cbReject())
    /* new content end */
  }
  then(onResolve, onReject) {
    this.cbResolve = onResolve
    this.cbReject = onReject
  }
}
const l1 = new LPromise((resolve, reject) = > resolve())
l1.then(
  res= > console.log('res'),
  err= > console.log('err'))Copy the code

Consider microtasks and macrotasks. We can use MutationObserver instead of setTimeout

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    /* new content start */
    const run = () = > this.cbResolve()
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')
    /* new content end */
  }
  #reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    /* new content start */
    const run = () = > this.cbReject()
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')
    /* new content end */
  }
  then(onResolve, onReject) {
    this.cbResolve = onResolve
    this.cbReject = onReject
  }
}
const l1 = new LPromise((resolve, reject) = > resolve())
l1.then(
  res= > console.log('res'),
  err= > console.log('err'))Copy the code

4. Chain call

Here’s the code, click here

In the original Promise. We can use then chain calls. Meaning that each then returns a new Promise.

Because it supports chain. So our previous cbResolve and cbReject can’t just hold a callback. To change back to an array, call the callback in each then. Are saved to the callback queue. Wait for resolve or reject to be called before executing all callbacks.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    /* new content start */
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    /* new content end */
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    /* new content start */
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        cbFn && cbFn()
      }
    }
    /* new content end */
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    /* new content start */
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        cbFn && cbFn()
      }
    }
    /* new content end */
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    /* new content start */
    return new LPromise((resolve, reject) = > {
      const cbResolve = () = > {
        onResolve && onResolve()
        resolve()
      }
      this.cbResolveQueue.push(cbResolve)
      const cbReject = () = > {
        onReject && onReject()
        reject()
      }
      this.cbRejectQueue.push(cbReject)
    })
    /* new content end */}}const l1 = new LPromise((resolve, reject) = > resolve())
l1.then(
  res= > console.log('res'),
  err= > console.log('err')
).then(
  res= > console.log('res'),
  err= > console.log('err'))Copy the code

At this point we’re done with the chain call, but we’ll find that if we return a new Promise, we won’t get the Promise result. So we have to add some criteria. We also find that we cannot receive the parameters of res or ERR at this point. So we also need to improve the parameter passing problem.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        /* new content start */
        cbFn && cbFn(res)
        /* new content end */}}const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        /* new content start */
        cbFn && cbFn(err)
        /* new content end */}}const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    return new LPromise((resolve, reject) = > {
      /* new content start */
      const cbResolve = res= > {
        const resolveRes = onResolve && onResolve(res)
        if (resolveRes instanceof LPromise) {
          resolveRes.then(resolve)
        } else {
          resolve(res)
        }
      }
      /* new content end */
      this.cbResolveQueue.push(cbResolve)
      /* new content start */
      const cbReject = err= > {
        onReject && onReject(err)
        reject(err)
      }
      /* new content end */
      this.cbRejectQueue.push(cbReject)
    })
  }
}
const l1 = new LPromise((resolve, reject) = > resolve('I am the resolve data passed in'))
l1.then(
  res= > {
    console.log('The res of the first then', res)
    return new LPromise((resolve, reject) = > resolve('Returned Promise'))},err= > console.log('First then err', err)
)
  .then(
    res= > console.log('The res of the second then', res),
    err= > console.log('Err for the second then', err)
  )
  .then(
    res= > console.log('The res of the third then', res),
    err= > console.log('Err for the third then', err)
  )
Copy the code

So far we have implemented a chain call to THEN

5. Implement catch method

Here’s the code, click here

An error callback is automatically added to the callback queue when a catch is called.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        cbFn && cbFn(res)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        cbFn && cbFn(err)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    return new LPromise((resolve, reject) = > {
      const cbResolve = res= > {
        const resolveRes = onResolve && onResolve(res)
        if (resolveRes instanceof LPromise) {
          resolveRes.then(resolve)
        } else {
          resolve(res)
        }
      }
      this.cbResolveQueue.push(cbResolve)
      const cbReject = err= > {
        onReject && onReject(err)
        reject(err)
      }
      this.cbRejectQueue.push(cbReject)
    })
  }
  /* new content start */
  catch(err) {
    this.then(undefined, err)
  }
  /* new content end */
}
const p1 = new LPromise((resolve, reject) = > reject('I'm an error message for P1'))
p1.then(res= > console.log(res)).catch(err= > console.log(err))
Copy the code

Resolve and reject static methods

Here’s the code, click here

These two static methods are relatively simple. Just return a Promise with a fixed state.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        cbFn && cbFn(res)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        cbFn && cbFn(err)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    return new LPromise((resolve, reject) = > {
      const cbResolve = res= > {
        const resolveRes = onResolve && onResolve(res)
        if (resolveRes instanceof LPromise) {
          resolveRes.then(resolve)
        } else {
          resolve(res)
        }
      }
      this.cbResolveQueue.push(cbResolve)
      const cbReject = err= > {
        onReject && onReject(err)
        reject(err)
      }
      this.cbRejectQueue.push(cbReject)
    })
  }
  /* new content start */
  static resolve(res) {
    return new LPromise(resolve= > resolve(res))
  }
  static reject(err) {
    return new LPromise((undefined, reject) = > reject(err))
  }
  /* new content end */
}
const p1 = LPromise.resolve('success')
console.log(p1)
const p2 = LPromise.reject('failure')
console.log(p2)
Copy the code

Implement the finally method

Here’s the code, click here

This implementation is similar to catch, except that the callback is executed regardless of success or failure.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        cbFn && cbFn(res)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        cbFn && cbFn(err)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    return new LPromise((resolve, reject) = > {
      const cbResolve = res= > {
        const resolveRes = onResolve && onResolve(res)
        if (resolveRes instanceof LPromise) {
          resolveRes.then(resolve)
        } else {
          resolve(res)
        }
      }
      this.cbResolveQueue.push(cbResolve)
      const cbReject = err= > {
        onReject && onReject(err)
        reject(err)
      }
      this.cbRejectQueue.push(cbReject)
    })
  }
  catch(err) {
    this.then(undefined, err)
  }
  /* new content start */
  finally(callback) {
    this.then(callback, callback)
  }
  /* new content end */
  static resolve(res) {
    return new LPromise(resolve= > resolve(res))
  }
  static reject(err) {
    return new LPromise((undefined, reject) = > reject(err))
  }
}
const p1 = new LPromise((resolve, reject) = > reject('I'm an error message for P1'))
p1.then(
  res= > console.log(res),
  err= > console.log(err)
).finally(() = > console.log('finally'))
Copy the code

Implement the RACE method

Here’s the code, click here

Race simply returns the result of the first successful execution. Success or failure. So we just need to iterate through the Promise and return the data as normal. Whoever completes the execution first returns first. Be careful to control the state to prevent multiple results from being returned. Race only needs to return the fastest result.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        cbFn && cbFn(res)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        cbFn && cbFn(err)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    return new LPromise((resolve, reject) = > {
      const cbResolve = res= > {
        const resolveRes = onResolve && onResolve(res)
        if (resolveRes instanceof LPromise) {
          resolveRes.then(resolve)
        } else {
          resolve(res)
        }
      }
      this.cbResolveQueue.push(cbResolve)
      const cbReject = err= > {
        onReject && onReject(err)
        reject(err)
      }
      this.cbRejectQueue.push(cbReject)
    })
  }
  catch(err) {
    this.then(undefined, err)
  }
  finally(callback) {
    this.then(callback, callback)
  }
  static resolve(res) {
    return new LPromise(resolve= > resolve(res))
  }
  static reject(err) {
    return new LPromise((undefined, reject) = > reject(err))
  }
  /* new content start */
  static race(promiseArr) {
    return new LPromise((resolve, reject) = > {
      let isContinue = true
      promiseArr.forEach(promise= > {
        promise.then(
          res= > {
            if (isContinue) {
              isContinue = false
              resolve(res)
            }
          },
          err= > {
            if (isContinue) {
              isContinue = false
              reject(err)
            }
          }
        )
      })
    })
  }
  /* new content end */
}
const p1 = new LPromise((resolve, reject) = > setTimeout(() = > resolve(1), 200))
const p2 = new LPromise((resolve, reject) = > setTimeout(() = > reject(2), 1000))
const p3 = new LPromise((resolve, reject) = > setTimeout(() = > resolve(3), 3000))
LPromise.race([p1, p2, p3]).then(
  res= > console.log('res', res),
  err= > console.log('err', err)
)
Copy the code

9, implement all method

Here’s the code, click here

The all method returns an array of results if all promises succeed, or if the first failed. We just need to iterate through the Promise array. Define a variable to hold the length of the current RES. If the length is equal to the length of the array, we resolve. Otherwise, reject the first failure.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        cbFn && cbFn(res)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        cbFn && cbFn(err)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    return new LPromise((resolve, reject) = > {
      const cbResolve = res= > {
        const resolveRes = onResolve && onResolve(res)
        if (resolveRes instanceof LPromise) {
          resolveRes.then(resolve)
        } else {
          resolve(res)
        }
      }
      this.cbResolveQueue.push(cbResolve)
      const cbReject = err= > {
        onReject && onReject(err)
        reject(err)
      }
      this.cbRejectQueue.push(cbReject)
    })
  }
  catch(err) {
    this.then(undefined, err)
  }
  finally(callback) {
    this.then(callback, callback)
  }
  static resolve(res) {
    return new LPromise(resolve= > resolve(res))
  }
  static reject(err) {
    return new LPromise((undefined, reject) = > reject(err))
  }
  static race(promiseArr) {
    return new LPromise((resolve, reject) = > {
      let isContinue = true
      promiseArr.forEach(promise= > {
        promise.then(
          res= > {
            if (isContinue) {
              isContinue = false
              resolve(res)
            }
          },
          err= > {
            if (isContinue) {
              isContinue = false
              reject(err)
            }
          }
        )
      })
    })
  }
  /* new content start */
  static all(promiseArr) {
    return new LPromise((resolve, reject) = > {
      const resArr = []
      const length = promiseArr.length
      promiseArr.forEach(p= > {
        p.then(
          res= > {
            resArr.push(res)
            if (resArr.length === length) {
              resolve(resArr)
            }
          },
          err= > reject(err)
        )
      })
    })
  }
  /* new content end */
}
const p1 = new LPromise((resolve, reject) = > setTimeout(() = > resolve(1), 200))
const p2 = new LPromise((resolve, reject) = > setTimeout(() = > reject(2), 1000))
const p3 = new LPromise((resolve, reject) = > setTimeout(() = > reject(3), 3000))
LPromise.all([p1, p2, p3]).then(
  res= > console.log('res', res),
  err= > console.log('err', err)
)
Copy the code

Implement the allSettled method

Here’s the code, click here

This method is similar to all. It just doesn’t matter whether the method succeeds or fails, as long as the Promise array completes. It will return all the results. We just need to determine if the implemented Promise length is equal to the array length. Resolve is resolved when it is agreed. And each time it executes, the returned value is saved in the returned RES in the specified format.

class LPromise {
  constructor(callbackFn) {
    this['[[PromiseState]]'] = 'pending'
    this['[[PromiseResult]]'] = undefined
    this.cbResolveQueue = []
    this.cbRejectQueue = []
    callbackFn(this.#resolve.bind(this), this.#reject.bind(this#)}resolve(res) {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = res
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbResolveQueue.shift())) {
        cbFn && cbFn(res)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen'#)}reject(err) {
    this['[[PromiseState]]'] = 'reject'
    this['[[PromiseResult]]'] = err
    const run = () = > {
      let cbFn
      while ((cbFn = this.cbRejectQueue.shift())) {
        cbFn && cbFn(err)
      }
    }
    const ob = new MutationObserver(run)
    ob.observe(document.body, { attributes: true })
    document.body.setAttribute('lpromise'.'layouwen')}then(onResolve, onReject) {
    return new LPromise((resolve, reject) = > {
      const cbResolve = res= > {
        const resolveRes = onResolve && onResolve(res)
        if (resolveRes instanceof LPromise) {
          resolveRes.then(resolve)
        } else {
          resolve(res)
        }
      }
      this.cbResolveQueue.push(cbResolve)
      const cbReject = err= > {
        onReject && onReject(err)
        reject(err)
      }
      this.cbRejectQueue.push(cbReject)
    })
  }
  catch(err) {
    this.then(undefined, err)
  }
  finally(callback) {
    this.then(callback, callback)
  }
  static resolve(res) {
    return new LPromise(resolve= > resolve(res))
  }
  static reject(err) {
    return new LPromise((undefined, reject) = > reject(err))
  }
  static race(promiseArr) {
    return new LPromise((resolve, reject) = > {
      let isContinue = true
      promiseArr.forEach(promise= > {
        promise.then(
          res= > {
            if (isContinue) {
              isContinue = false
              resolve(res)
            }
          },
          err= > {
            if (isContinue) {
              isContinue = false
              reject(err)
            }
          }
        )
      })
    })
  }
  static all(promiseArr) {
    return new LPromise((resolve, reject) = > {
      const resArr = []
      const length = promiseArr.length
      promiseArr.forEach(p= > {
        p.then(
          res= > {
            resArr.push(res)
            if (resArr.length === length) {
              resolve(resArr)
            }
          },
          err= > reject(err)
        )
      })
    })
  }
  /* new content start */
  static allSettled(promiseArr) {
    return new LPromise(resolve= > {
      const resArr = new Array(promiseArr.length)
      let num = 0
      promiseArr.forEach(p= > {
        let obj = {}
        p.then(
          res= > {
            obj.status = 'fulfilled'
            obj.value = res
            resArr[num] = obj
            num++
            if (num === resArr.length) resolve(resArr)
          },
          err= > {
            obj.status = 'rejected'
            obj.reason = err
            resArr[num] = obj
            num++
            if (num === resArr.length) resolve(resArr)
          }
        )
      })
    })
  }
  /* new content end */
}
const p1 = new LPromise((resolve, reject) = > setTimeout(() = > resolve(1), 200))
const p2 = new LPromise((resolve, reject) = > setTimeout(() = > reject(2), 1000))
const p3 = new LPromise((resolve, reject) = > setTimeout(() = > reject(3), 3000))
LPromise.allSettled([p1, p2, p3]).then(
  res= > console.log('res', res),
  err= > console.log('err', err)
)
Copy the code

End

This article to achieve the Promise is not perfect, just about the realization of the principle with you again. The source code for Promise was not written in JS, so we had to use JS imitation whenever possible. Lustful gentlemen added a more perfect version.

Exchange learning ~

Wechat: gdgzyw Github: www.github.com/layouwen