Секрет обещания (анализ и реализация принципа обещания)

JavaScript

написать впереди

Эта статья поможет вам начать с декомпозиции промисов и их реализации шаг за шагом. Но прежде чем читать, вам нужно лучше понять использование, и может быть легче понять статью в сочетании с использованием.

структура

Сначала рассмотрим простое использование.

const promise = new Promise((resolve, reject) => {
   setTimeout(() => {
       resolve('success')
   })
})
.then(value => { ... }, reason => { ... })
.catch(error => { ... })

Конструктор Promise получает обратный вызов, который является исполнителем, о котором будет сказано ниже, параметры разрешения и отклонения исполнителя также являются двумя функциями. Ответственный за изменение состояния экземпляра обещания и его значения, обратный вызов в функции then выполняется после изменения состояния.

Примечание. Это не функция then, которая выполняется после изменения состояния, а функция обратного вызова в then, которая выполняется после изменения состояния. Метод then помещает обратные вызовы в очередь выполнения, и после изменения состояния промиса функции в очереди будут выполняться одна за другой.

Если вы хотите реализовать простейший класс промисов, что должна содержать внутренняя структура?

  • Статус: выполнено, отклонено, на рассмотрении.
  • Значение: значение обещания.
  • Исполнитель: предоставляет запись для изменения состояния промиса.
  • Методы разрешения и отклонения: первый изменяет обещание на выполненное, второй — на отклоненное. Его можно контролировать в исполнителе для разрешения или отклонения в соответствии с фактическим бизнесом.
  • затем метод: получает два обратных вызова, onFulfilled, onRejected. Выполняется после того, как статус обещания становится выполненным или отклоненным соответственно.Это включает в себя операцию регистрации обратных вызовов в две очереди выполнения, которые будут обсуждаться позже.
const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'

class NewPromise {
  constructor(handler) {
    this.state = PENDING
    this.value = undefined
    this.successCallback = []
    this.failureCallback = []
    try {
      handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {
      this.reject(e)
    }
  }

  // resolve和reject方法
  resolve(value) { ... }
  reject(reason) { ... }

  // then方法
  then(onFulfilled, onRejected) { ... }
}

Как реализована каждая часть структуры?

Исполнитель обещания

Исполнитель — это обратный вызов, который передается, когда мы инициализируем обещание, и это точка входа для нас, чтобы работать с обещанием, поэтому реализация исполнителя несложна, то есть обратный вызов, который мы передаем, выполняется.

class NewPromise {
  ...
  handler(resolve.bind(this), reject.bind(this))
  ...
}

На самом деле исполнитель примет два обратных вызова, разрешение и отклонение. Они действительно выполняют работу по изменению состояния промиса.

решить и отклонить

На самом деле, есть две функции, которые передаются в исполнитель в качестве параметров, а что они делают, не сложняется:

  • Изменить состояние промиса
  • Использовать полученное значение в качестве значения обещания
  • Выполните обратные вызовы, зарегистрированные в, а затем по очереди
const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'

class NewPromise {
  constructor(handler) {
    this.state = PENDING
    this.value = undefined

    // 两个队列,后面会讲到
    this.successCallback = []
    this.failureCallback = []
    try {
      // 执行器,由于resolve和reject中用到了this,这里需要bind一下
      handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {
      this.reject(e)
    }
  }

  resolve(value) {
    if (this.state !== PENDING) return
    this.state = FULFILLED
    this.value = value
    // 用setTimeout模拟异步方式
    setTimeout(() => {
      this.successCallback.forEach(item => {
        item(value)
      })
    })
  }

  reject(reason) {
    if (this.state !== PENDING) return
    this.state = REJECTED
    this.value = reason
    setTimeout(() => {
      this.failureCallback.forEach(item => {
        setTimeout(item(reason))
      })
    })
  }
}

Взгляните на их реализацию, измените состояние, присвойте значение. Самый важный момент: прокрутите обратные вызовы, зарегистрированные в очереди методом then. Спецификация требует, чтобы обратные вызовы выполнялись асинхронно, что гарантирует, что все обратные вызовы были зарегистрированы до момента выполнения всех обратных вызовов, поэтому вот симуляция с setTimeout.

затем метод:

(перевод сСпецификация Обещание/A+)

Обещание должно предоставлять метод then для доступа к текущему или конечному значению этого обещания. Метод then имеет два параметра: onFulfilled, onRejected, оба необязательные. Здесь есть несколько правил относительно этих двух параметров:

Когда onFulfilled и onRejected не являются функциями, их нужно игнорировать.

На самом деле игнорирование означает, что если это не функция, то ей присваивается функция по умолчанию, а возвращаемое значение — это значение промиса, которому потом принадлежит. Это сделано для того, чтобы, когда функция then() не передала обратный вызов, можно было передать значение промиса. Сценарий следующий:

promise(resolve => resolve('success'))
    .then()
    .then(function(value) {
     console.log(value)
    })

С точки зрения конкретной реализации, когда это не функция, вы можете назначить ей функцию по умолчанию или вы можете напрямую вызвать разрешение или отклонение во вновь возвращенном промисе, чтобы передать значение вниз для достижения эффекта игнорирования.

когда onFulfilled является функцией

  • Должен вызываться, когда состояние текущего промиса становится выполненным, а значение разрешенного промиса является его первым параметром.
  • не может быть вызван до выполнения
  • можно вызвать только один раз

когда onRejected является функцией

  • Должен вызываться, когда состояние текущего обещания становится отклоненным, а значение отклоненного обещания является его первым параметром. не может быть вызван до отклонения,
  • Может быть вызван не более одного раза.

затем может вызываться несколько раз

  • Когда статус промиса становится выполненным, все onFulfilled будут вызываться в том порядке, в котором они были впервые зарегистрированы в методе then.
  • Когда состояние обещания становится отклоненным, все onRejected будут вызываться в том порядке, в котором они были впервые зарегистрированы в методе then, например так:
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('success'))
  })
  promise.then(res => {
    console.log(res, '第一次');
  })
  promise.then(res => {
    console.log(res, '第二次');
  })

Ввиду этой ситуации нам нужно поддерживать две очереди внутри реализованного нами промиса.Элементами очереди являются callback-функции (onFulfilled, onRejected), зарегистрированные в методе then.Каждый раз, когда then вызывается, callback регистрируется в методе then. очередь, и они будут выполняться последовательно при изменении состояния промиса.

Возвращает обещание для простой цепочки

 promise2 = promise1.then(onFulfilled, onRejected);

Состояние обещания (то есть обещания2), возвращенного к этому времени, зависит от возвращаемого значения его функции обратного вызова (onFulfilled или onRejected) или состояния обещания1 следующим образом:

  • Возвращаемое значение onFulfilled или onRejected — это значение x, тогда состояние promise2 — разрешение, а значение — x.
  • Если выполнение onFulfilled или onRejected терпит неудачу и выдается объект ошибки e, то состояние promise2 отклоняется и значением является этот объект ошибки e
  • Если onFulfilled не является функцией, но состояние promise1 становится выполненным, то состояние promise2 также выполняется с тем же значением, что и promise1
  • Если onRejected не является функцией, но состояние обещания1 становится отклоненным, то состояние обещания2 также отвергается, и значение совпадает с обещанием1 (это значение является причиной, как и обещание2)

根据这些原则,我画了一张图放在了下文中

выполнить

Мы узнали о методе then выше.В сочетании с определением и обычным использованием мы можем предположить, что метод then в нашем собственном промисе должен делать следующие вещи:

  • возвращает новый экземпляр обещания
  • Обещание, которому затем принадлежит, находится в состоянии ожидания, а обратные вызовы (onFulfilled, onRejected) затем помещаются в очереди выполнения для ожидания выполнения, а функции в этих двух очередях выполняются только тогда, когда состояние обещания который затем принадлежит, изменяется. Гарантирует время выполнения onFulfilled и onRejected в спецификации.
  • Когда состояние промиса, к которому затем принадлежит, не является ожидающим, обратные вызовы в очереди выполнения выполняются последовательно, а затем состояние нового промиса определяется в соответствии с измененным состоянием и возвращаемым значением обратного вызова.
    • Например:
    const promise1 = new Promise((resolve, reject) =>{ ... })
    const promise2 = promise1.then(value => {
      return 'success'
    }, reason => {
      return 'failed'
    })
    
    Предполагая, что promise1 разрешается, так как затем передается обратный вызов, представляющий onFulfilled, и возвращаемое значение является успешным, тогда promise2 будет разрешен со значением успеха. Предполагая, что обещание2 отклонено, поскольку тогда передается обратный вызов, представляющий onRejected, и возвращаемое значение не выполнено, тогда обещание2 будет отклонено, а причина не удалась

Следующим шагом является реализация метода then сначала в структуре:

class NewPromise {
  constructor(handler) {
    this.state = PENDING
    this.value = undefined

    // 两个队列,存放onFulfiled 和 onRejected
    this.successCallback = []
    this.failureCallback = []
    try {
      handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {
      this.reject(e)
    }
  }
  then(onFulfilled, onRejected) {
    return new NewPromise((resolveNext, rejectNext) => {
      // pengding状态向队列中注册回调
      if (state === PENDING) {
        successCallback.push(onFulfilled)
        failureCallback.push(onRejected)
      }

      // 要保证在当前promise状态改变之后,再去通过resolveNext或者rejectNext改变新的promise的状态
      if (state === FULFILLED) {
        resolveNext(value)
      }
      if (state === REJECTED) {
        rejectNext(value)
      }
    })
  }
}

Приведенная выше структура в основном реализует общую логику функции then, но не достигает эффекта определения состояния нового промиса на основе результатов выполнения двух обратных вызовов onFulfilled и onRejected. Просто поместите их в соответствующие очереди выполнения.

Состояние обещания, возвращенное к тому времени, связано с результатами выполнения onFulfilled и onRejected. Я организовал картину в соответствии со спецификацией и реальной ситуацией:

then.jpg

Затем давайте реализуем это с помощью кода (просто возьмем в качестве примера выполнение onFulfilled)

    try {
      // 正常情况
      if (typeof onFulfilled !== 'function') {
        // 不是函数,直接忽略,将then所属的promise作为then返回的promise的值resolve来做到值的传递
        resolveNext(value)
      } else {
        // 获取then函数回调的执行结果
        const res = onFulfilled(value)
        if (res instanceof NewPromise) {
          // 当执行结果返回的是一个promise实例,等待这个promise状态改变后再改变then返回的promise的状态
          res.then(resolveNext, rejectNext)
        } else {
          // 当返回值是普通值,将其作为新promise的值resolve
          resolveNext(res)
        }
      }
    } catch (e) {
      // 出现异常,新promise的状态变为rejected,reason就是错误对象
      rejectNext(e)
    }

Всю часть нужно поставить в очередь, чтобы дождаться изменения состояния промиса, которому потом принадлежит, и затем выполнить, тем самым изменив состояние возвращенного к тому времени промиса. Итак, нам нужно завернуть этот кусок. В совокупности это:

class NewPromise {
  constructor(handler) {
    this.state = PENDING
    this.value = undefined

    // 两个队列,存放onFulfiled 和 onRejected
    this.successCallback = []
    this.failureCallback = []
    try {
      handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {
      this.reject(e)
    }
  }
  then(onFulfilled, onRejected) {
    const { state, value } = this
    return new NewPromise((resolveNext, rejectNext) => {
      const resolveNewPromise = value => {
        try {
          // 正常情况
          if (typeof onFulfilled !== 'function') {
            // 不是函数,直接忽略,将then所属的promise作为返回的新的promise的值resolve,来做到值的传递
            resolveNext(value)
          } else {
            // 获取then函数回调的执行结果
            const res = onFulfilled(value)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个promise实例,等待这个promise状态改变后再改变then返回的promise的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新promise的值resolve
              resolveNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新promise的状态变为rejected,reason就是错误对象
          rejectNext(e)
        }
      }
      const rejectNewPromise = reason => {
        try {
          // 正常情况
          if (typeof onRejected !== 'function') {
            // 不是函数,直接忽略,将then所属的promise作为then返回的promise的值reject来做到值的传递
            rejectNext(reason)
          } else {
            // 获取then函数回调的执行结果
            const res = onRejected(reason)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个promise实例,等待这个promise状态改变后再改变then返回的promise的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新promise的值reject
              rejectNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新promise的状态变为rejected,reason就是错误对象
          rejectNext(e)
        }
      }
      if (state === PENDING) {
        this.successCallback.push(resolveNewPromise)
        this.failureCallback.push(rejectNewPromise)
      }
      // 要保证在当前promise状态改变之后,再去改变新的promise的状态
      if (state === FULFILLED) {
        resolveNewPromise(value)
      }
      if (state === REJECTED) {
        rejectNewPromise(value)
      }
    })
  }
}

В нашей собственной реализации мы определяем два массива как очереди задач для хранения зарегистрированных обратных вызовов. В самом обещании, Метод then заключается в регистрации обратного вызова в очереди микрозадач. Подождите, пока состояние обещания не изменится, прежде чем выполнять задачи в очереди микрозадач. Микрозадачи концептуально можно считать асинхронными задачами, что также подтверждает утверждение о том, что в спецификации обратный вызов then должен выполняться асинхронно.

О некоторых знаниях о цикле событий я резюмировал статью,Сегодня я понял механизм цикла обработки событий JS.

поймать функцию

Функция catch используется для обработки исключений.Когда состояние обещания становится отклоненным, причина ошибки перехватывается.

Затем, предполагая отсутствие перехвата, вы также можете перехватить эту ошибку во втором обратном вызове (onRejected) функции then. И catch возвращает обещание, поэтому поведение такое же, как при вызове Promise.prototype.then(undefined, onRejected)

catch(onRejected) {
  return this.then(undefined, onRejected)
}

метод решения

Promise.resolve(value) возвращает объект обещания, который используется для переноса входящего значения значения в объект обещания.

Так какой смысл это делать? На самом деле значение может быть неопределенным значением, может быть или не быть промисом, может быть, вы можете вызвать метод then, а может и нет. Однако поведение операции со значением можно унифицировать с помощью метода разрешения. Например:

const promise = function() {
  if (shouldBePromise) {
    return new Promise(function(resolve, reject) {
        resolve('ok')
    })
  }
  return 'ok'
}
promise().then(() => {
    ...
})

Результат, возвращаемый промисом, зависит от shouldBePromise.Если shouldBePromise ложно, обещание возвращает строку ok, и метод then не может быть вызван ниже.

В это время его можно обернуть с помощью Promise().resolve, чтобы возвращаемый промис всегда был экземпляром промиса, что обеспечивает плавный вызов метода then.

Promise.resolve(promise()).then(() => {
    ...
})

Подводя итог характеристикам: параметры Promise.resolve, если:

  • Если не пройдено, верните решенный промис
  • Является объектом, который можно использовать (то есть с методом «тогда»), состояние возвращаемого промиса будет меняться при изменении состояния этого объекта, и оно будет соответствовать состоянию объекта.
  • Является нормальным значением, возвращает обещание в разрешенном состоянии, значение обещания - это нормальное значение
  • является объектом Promise, вернуть этот объект
  static resolve(value) {
    // value不存在,直接返回一个resolved状态的promise
    if (!value) {
      return new NewPromise(function (resolve) {
        resolve()
      })
    }
    // value是promise实例,直接返回
    // 在这里需要首先判断是否是promise实例,再进行下边的判断
    // 因为我们自己构造的promise也是是object,也有then方法
    if (value instanceof NewPromise) {
      return value
    }
    // 是thenable对象,返回的新的promise实例需要在value状态改变后再改变,且状态跟随value的状态
    if (typeof value === 'object' && typeof value.then === 'function') {
      return new NewPromise((resolve, reject) => {
        value.then(resolve, reject)
      })
    }
    // value是普通值,返回新的promise并resolve这个普通值
    return new NewPromise(resolve => {
      resolve(value)
    })
  }

метод отклонения

Метод reject относительно прост по сравнению с Resolve. Он всегда возвращает объект обещания отклонения. Причина отклонения — это причина, которую мы передали.

  static reject(reason) {
    return new NewPromise((resolve, reject) => {
      reject(reason)
    })
  }

наконец метод

То, что возвращается, является обещанием, и функция заключается в том, что когда обещание заканчивается, независимо от того, выполнен результат или отклонен, будет выполнена функция обратного вызова. Состояние и значение нового возвращаемого промиса зависят от исходного промиса.

finally(callback) {
  // 返回值是promise对象,回调在then中执行,也就符合了promise结束后调用的原则
  return this.then(
    // then方法的onFulfiled 和 onRejected都会被传入,保证无论resolved或rejected都会被执行

    // 获取到promise执行成功的结果,将这个结果作为返回的新promise的值
    res => NewPromise.resolve(callback())
        .then(() => {
          return res
        }),
    // 获取执行失败的结果。原理同上
    error => NewPromise.resolve(callback())
        .then(() => {
          throw error
        })
  )
}

все методы

Обещайте. Все (paral) получают массив параметров и возвращает новый экземпляр обещания. Когда экземпляр обещания в рамках параметров в пределах массива или разрешения всех параметров завершен, новое обещание возврата разрешится. Обещание любого провала в массиве (отклонено), вновь возвращенное поражение обещания, результатом является первой причиной провала неудачного обещания.

const p1 = Promise.resolve(1),
coint p2 = Promise.resolve(2),
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {
    console.log(results);  // [1, 2, 3]
});

Видно, что метод all должен возвращать новый экземпляр обещания, а затем управлять состоянием и значением нового экземпляра обещания в соответствии с выполнением полученного массива параметров.

  static all(instanceList) {
    return new NewPromise((resolve, reject) => {
      // 定义存放结果的数组
      const results = []
      let count = 0
      if (instanceList.length === 0) {
        resolve(results)
        return
      }
      instanceList.forEach((item, index) => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用this.resolve方法包装一层
        this.resolve(item).then(res => {
          results[index] = res
          count++
          // 当都执行完,resolve新返回的promise
          if (count === instanceList.length) {
            resolve(results)
          }
        }, error => {
          // 一旦有一个出错,就reject新返回的promise
          reject(error)
        })
      })
    })
  }

После реализации хорошо видно, что метод all будет выполнять все промисы параллельно, а результаты будут выводиться в порядке входящего массива промисов. Это напоминает мне вопрос, с которым я столкнулся в предыдущем интервью: Все запросы одновременно выводятся по порядку. Этого можно достичь с помощью Promise.all. Но на самом деле будут случаи, когда запрос не пройден, поэтому лучше использовать Promise.allSettled, о котором будет сказано ниже.

метод allSettled

Если finally предоставляет способ выполнения кода в случае успеха одного промиса или нет, то allSettled предоставляет тот же метод операции для успешного выполнения нескольких промисов.

Метод Promise.allSettled() возвращает промис, который разрешается после того, как все заданные промисы были разрешены или отклонены, и каждый объект описывает результат каждого промиса.

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));
// expected output:
// "fulfilled"
// "rejected"

В отличие от Promise.all, после сбоя одного выполнения вы не можете получить характеристики момента времени, когда все обещания выполняются. В методе allSettled, независимо от того, является ли промис успешным или нет, после завершения всех промисов можно получить этот момент времени. Потому что новое обещание, которое он возвращает, всегда разрешено, а значение представляет собой описание результата выполнения всех обещаний.

[
  {"status":"rejected","reason":"失败"},
  {"status":"fulfiled","value":"成功"}
]

Чтобы реализовать его, вам нужно записать результаты в массив при выполнении каждого промиса и, наконец, разрешить массив результатов после выполнения всех промисов, изменив состояние нового возвращенного промиса.

  static allSettled(instanceList) {
    return new NewPromise((resolve, reject) => {
      const results = []
      let count = 0
      if (instanceList.length === 0) {
        resolve([])
        return
      }
      // 定义一个函数,来生成结果数组
      const generateResult = (result, i) => {
        count++
        results[i] = result
        // 一旦全部执行完成,resolve新返回的promise
        if (count === instanceList.length) {
          resolve(results)
        }
      }
      instanceList.forEach((item, index) => {
        // 在每个promise完成后将状态记录到结果数组中
        this.resolve(item).then(
          value => {
            generateResult({
              status: FULFILLED,
              value
            }, index)
          },
          reason => {
            generateResult({
              status: REJECTED,
              reason
            }, index)
          }
        )
      })
    })
  }

метод гонки

Подобно методу all, он принимает в качестве параметра массив экземпляров и возвращает новое обещание. Но разница в том, что после того, как промис в массиве экземпляров будет выполнен успешно или неудачно, возвращенный промис будет успешным или неудачным.

  static race(instanceList) {
    return new NewPromise((resolve, reject) => {
      if (instanceList.length === 0) {
        resolve([])
        return
      }
      instanceList.forEach(item => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用this.resolve方法包装一层
        this.resolve(item).then(res => {
          // 一旦有一个resolve了,那么新返回的promise状态就被resolve
          resolve(res)
        }, error => {
          reject(error)
        })
      })
    })
  }

полный код

На данный момент реализовано относительно полное обещание, и код выглядит следующим образом:

class NewPromise {
  constructor(handler) {
    this.state = PENDING
    this.value = undefined
    this.successCallback = []
    this.failureCallback = []
    try {
      handler(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {
      // 执行器出现错误需要reject
      this.reject(e)
    }
  }

  resolve(value) {
    if (this.state !== PENDING) return
    this.state = FULFILLED
    this.value = value
    // 规范中要求then中注册的回调以异步方式执行,保证在resolve执行所有的回调之前,
    // 所有回调已经通过then注册完成
    setTimeout(() => {
      this.successCallback.forEach(item => {
        item(value)
      })
    })
  }
  reject(reason) {
    if (this.state !== PENDING) return
    this.state = REJECTED
    this.value = reason
    setTimeout(() => {
      this.failureCallback.forEach(item => {
        item(reason)
      })
    })
  }
  then(onFulfilled, onRejected) {
    const { state, value } = this
    return new NewPromise((resolveNext, rejectNext) => {
      const resolveNewPromise = value => {
        try {
          // 正常情况
          if (typeof onFulfilled !== 'function') {
            // 不是函数,直接忽略,将then所属的promise作为then返回的promise的值resolve来做到值的传递
            resolveNext(value)
          } else {
            // 获取then函数回调的执行结果
            const res = onFulfilled(value)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个promise实例,等待这个promise状态改变后再改变then返回的promise的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新promise的值resolve
              resolveNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新promise的状态变为rejected,reason就是错误对象
          rejectNext(e)
        }
      }
      const rejectNewPromise = reason => {
        try {
          // 正常情况
          if (typeof onRejected !== 'function') {
            // 不是函数,直接忽略,将then所属的promise作为then返回的promise的值reject来做到值的传递
            rejectNext(reason)
          } else {
            // 获取then函数回调的执行结果
            const res = onRejected(reason)
            if (res instanceof NewPromise) {
              // 当执行结果返回的是一个promise实例,等待这个promise状态改变后再改变then返回的promise的状态
              res.then(resolveNext, rejectNext)
            } else {
              // 当返回值是普通值,将其作为新promise的值reject
              rejectNext(res)
            }
          }
        } catch (e) {
          // 出现异常,新promise的状态变为rejected,reason就是错误对象
          rejectNext(e)
        }
      }
      if (state === PENDING) {
        this.successCallback.push(resolveNewPromise)
        this.failureCallback.push(rejectNewPromise)
      }
      // 要保证在当前promise状态改变之后,再去改变新的promise的状态
      if (state === FULFILLED) {
        resolveNewPromise(value)
      }
      if (state === REJECTED) {
        rejectNewPromise(value)
      }
    })
  }
  catch(onRejected) {
    return this.then(undefined, onRejected)
  }
  finally(callback) {
    // 返回值是promise对象,回调在then中执行,也就符合了promise结束后调用的原则
    return this.then(
      // then方法的onFulfiled 和 onRejected都会被传入,保证无论resolved或rejected都会被执行

      // 获取到promise执行成功的结果,将这个结果作为finally返回的新的promise的值
      res => NewPromise.resolve(callback())
          .then(() => {
            return res
          }),
      // 获取执行失败的结果。原理同上
      error => NewPromise.resolve(callback())
          .then(() => {
            throw error
          })
    )
  }
  static allSettled(instanceList) {
    return new NewPromise((resolve, reject) => {
      const results = []
      let count = 0
      if (instanceList.length === 0) {
        resolve([])
        return
      }
      // 定义一个函数,来生成结果数组
      const generateResult = (result, i) => {
        count++
        results[i] = result
        // 一旦全部执行完成,resolve新返回的promise
        if (count === instanceList.length) {
          resolve(results)
        }
      }
      instanceList.forEach((item, index) => {
        // 在每个promise完成后将状态记录到结果数组中
        this.resolve(item).then(
          value => {
            generateResult({
              status: FULFILLED,
              value
            }, index)
          },
          reason => {
            generateResult({
              status: REJECTED,
              reason
            }, index)
          }
        )
      })
    })
  }
  static resolve(value) {
    // value不存在,直接返回一个resolved状态的promise
    if (!value) {
      return new NewPromise(function (resolve) {
        resolve()
      })
    }
    // value是promise实例,直接返回
    // 在这里需要首先判断是否是promise实例,再进行下边的判断
    // 因为我们自己构造的promise也是是object,也有then方法
    if (value instanceof NewPromise) {
      return value
    }
    // 是thenable对象,返回的新的promise实例需要在value状态改变后再改变,且状态跟随value的状态
    if (typeof value === 'object' && typeof value.then === 'function') {
      return new NewPromise((resolve, reject) => {
        value.then(resolve, reject)
      })
    }
    // value是普通值,返回新的promise并resolve这个普通值
    return new NewPromise(resolve => {
      resolve(value)
    })
  }
  static reject(reason) {
    return new NewPromise((resolve, reject) => {
      reject(reason)
    })
  }
  static all(instanceList) {
    return new NewPromise((resolve, reject) => {
      // 定义存放结果的数组
      const results = []
      let count = 0
      if (instanceList.length === 0) {
        resolve(results)
        return
      }
      instanceList.forEach((item, index) => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用this.resolve方法包装一层
        this.resolve(item).then(res => {
          results[index] = res
          count++
          // 当都执行完,resolve新返回的promise
          if (count === instanceList.length) {
            resolve(results)
          }
        }, error => {
          // 一旦有一个出错,就reject新返回的promise
          reject(error)
        })
      })
    })
  }
  static race(instanceList) {
    return new NewPromise((resolve, reject) => {
      if (instanceList.length === 0) {
        resolve([])
        return
      }
      instanceList.forEach(item => {
        // 由于实例列表中的每个元素可能是各种各样的,所以要用this.resolve方法包装一层
        this.resolve(item).then(res => {
          // 一旦有一个resolve了,那么新返回的promise状态就被resolve
          resolve(res)
        }, error => {
          reject(error)
        })
      })
    })
  }
}

конечные титры

Если вы хотите увидеть больше технических статей, написанных мной, то можете обратить внимание на паблик аккаунт: one front end

qrcode.jpg