Погрузитесь в обещания

внешний интерфейс JavaScript Promise ECMAScript 6 ECMAScript 8
Погрузитесь в обещания
> new Promise((resolve, reject) => setTimeout(resolve, 1000, 'foo'))  
> .then(console.log)  
> // foo (1s后)

При использовании Promise наше самое простое понимание и использование состоит в том, чтобы предоставить асинхронный результат для разрешения в качестве параметра, подобного приведенному выше коду, а затем передать пользовательскую функцию методу then в качестве функции обработки результата. Но что такое параметры разрешения и отклонения? Каков основной способ работы за этим? Давайте сначала посмотрим на это с нормативной точки зрения.

Ссылка: Обещания ES8

TL;DR

  • Рабочий механизм обещания аналогичен обратному вызову, и оба используют внутреннюю абстрактную операцию Job для достижения асинхронности.
  • Функции разрешения/отклонения в конструкторе промиса создаются внутренне.Параметры, передаваемые при их вызове, являются результатами, которые должны быть разрешены, и они вставляются в очередь заданий вместе с функцией обработчика, переданной пользователем, где обещание было были сохранены. Переданный параметр также может быть обещанием, которое используется внутри Promise.all/race.
  • Promise.prototype.then решает, следует ли немедленно получить результат, хранящийся в промисе, и вставить его прямо в очередь заданий вместе с обработчиком в параметре в соответствии с текущим состоянием промиса, или связать его с промисом в качестве обработчика результата. первый. затем неявно вызывает конструктор Promise для создания нового обещания и возврата.
  • Promise.all сначала создает новый промис, затем сначала инициализирует пустой массив результатов и счетчик для подсчета разрешенных промисов, затем выполняет итерацию, для каждого значения итерации он создает промис для него и устанавливает затем этого промиса, чтобы добавить результат и счетчик в массив результатов -- и разрешить окончательный результат, когда счетчик уменьшится до 0.
  • Promise.race также создаст новый основной промис, а затем в основном на основе ограничения, что промисы могут быть разрешены только один раз.Для каждого значения итерации будет создан другой промис, а тот, который разрешается первым, будет разрешен основным промисом сначала и вернуть результат.

new Promise(executor)

Начнем с конструктора Promise, который является значением свойства Promise глобального объекта, поэтому мы можем вызывать его непосредственно в среде браузера, точно так же, как String, Array и эти конструкторы.

new Promise(executor)Первым шагом является создание нового объекта в соответствии с прототипом Promise, как и любого другого конструктора, и инициализация нескольких внутренних слотов.[[PromiseState]],[[PromiseResult]],[[PromiseFullfillReactions]],[[PromiseRejectReactions]],[[PromiseIsHandled]]Чтобы записать некоторую связанную информацию, вы можете примерно определить их роль по имени, и мы упомянем об этом позже для деталей. Здесь их начальные значения кроме[[PromiseResult]]Заказ "в ожидании", пустой список, пустой список, ложь.

На следующем шаге ES сгенерирует обещание для разрешения обещания на основе объекта обещания.resolve functionи отказаться от обещанияreject function. Затем вызовите исполнителя сresolve functionа такжеreject functionВ качестве параметра, если в этом процессе есть ошибка, просто отклоните промис напрямую. Наконец вернуть обещание.

Итак, что такое решение и что такое отказ. Мы знаем состояние Обещания, которое[[PromiseState]]Есть три значения: ожидание, выполнено, отклонено, сreject functionВы можете отклонить обещание и изменить его состояние с ожидания на отклонение. ноresolve functionЛибо выполнить промисы, чтобы изменить состояние промисов с ожидающих на выполненные, либо отклонить промисы.

Такresolve functionа такжеreject functionЧто он сделал?

Первый взглядreject function, сначала, когда он сгенерирован, он будет инициализирован[[Promise]]а также[[AlreadyResolved]]слот, то есть связать его с обещанием. Во время выполнения передается причина параметра, и только когда[[AlreadyResolved]]Это false, то есть он будет вызываться и возвращаться только тогда, когда он не разрешен и статус находится в ожидании.RejectPromise, передать параметры обещания и причины, чтобы отклонить обещание, иначе вернуть неопределенное значение.
RejectPromise(promise, reason), в дополнение к тому, чтобы положить[[PromiseState]]В дополнение к изменению с ожидающего на отклоненное, он также изменит результат обещания.[[PromiseResult]]настроен на причину и удалит обещание[[PromiseRejectReactions]]Записанные записи (полагал, что читатели уже поняли одну операцию по сохранению этого внутреннего слота), и использоватьTriggerPromiseReactionsЭти записи вызовов для дальнейшей обработки и отклонения входящей причины причины. похожий,resolve functionиспользуется вFullfillPromise(promise, value)Операция изменяет состояние обещания на выполненное, извлекая[[PromiseFullfillReactions]]стоимость звонкаTriggerPromiseReactionsи передать выполненное значение результата.

TriggerPromiseReactions(reactions, argument)позвонюEnqueueJob("PromiseJobs", PromiseReactionJob, <<reactions, argument>>), Будет объяснено подробно снова.

увидеть сноваresolve function,а такжеreject functionТочно так же, когда он генерируется, он связан с обещанием. Во время выполнения параметр, который мы передаем, называется разрешением. Возвращает неопределенное значение, если обещание разрешено. После этого ситуация усложняется.

  1. Если пользователь передает само обещание в функцию разрешения в качестве разрешения параметра, будет создана ошибка TypeError, выброшена и вызванаRejectPromise, параметр Reason — это TypeError.
  2. Если тип разрешения не Object, вызовитеFulfillPromise(promise, resolution).
  3. Остальные случаи случаев, когда разрешение является объектом с тогдашним (обещанием), кроме самого себя.
    • Если разрешение — это объект без then, тоRejectPromise.
    • Если есть атрибут then, но его нельзя вызвать, такжеFulfillPromise, .
    • Если есть атрибут then и его можно вызвать, тоEnqueueJob("PromiseJobs", PromiseResolveThenableJob, <<promise, resolution, thenAction>>).

в описанииEnqueueJobПрежде взгляните на то, что такое Иов. Проще говоря, это как внутри механизма обратного вызова добиться: «Когда нет других запущенных ES, инициализировать и выполнить свой собственный соответствующий ES». В очереди FIFO задания у нас есть ожидающее выполнение, и текущая среда выполнения, в которой запущен контекст выполнения и стек контекста выполнения, когда последние два пусты, будет выполняться первой очередью заданий.

ES предусматривает, что в реализации должно быть не менее двух очередей заданий,ScriptJobsа такжеPromiseJobs. когда мы звонимEnqueueJob("PromiseJobs", ...), задания, которые необходимо выполнить, и их параметры вставляются вPromiseJobsэта очередь. Как вы можете видеть, есть два вида Jobs под Promise.

  1. PromiseReactionJob(reaction, argument)
    реакция имеет три внутренних слота[[Capability]],[[Type]]а также[[Handler]],Соответственно[[关联的 promise 及相关的resolve function 和 reject function]],[[类别]],[[handler]]. Если пользователь не указывает handler(undefined), в качестве результата используется аргумент в зависимости от того, является ли категория «Выполнить» или «Отклонить». Если указан обработчик, используйте его для дальнейшей обработки аргумента. Наконец, в соответствии с этим результатом, для обработки и возврата используются функция разрешения и функция отклонения.
  2. PromiseResolveThenableJob(promiseToResolve, thenable, then)
    Создайте функцию разрешения и функцию отклонения, связанную с promiseToResolve. Используйте then в качестве вызывающей функции, thenable как this, а также функцию разрешения и функцию отклонения в качестве параметров для вызова и возврата.

Promise.prototype.then(onfulfilled, onrejected)

Первый заключается в созданииpromiseCapability, который содержит новое обещание и связанный с нимresolve functionа такжеreject function. Генерация обещания заключается в создании обещания, как при обычном использовании конструктора обещания, но исполнитель, переданный конструктору, автоматически создается внутри, а функция состоит в том, чтобы записать функцию разрешения/отклонения вPromiseCapabilityсередина. Создайте два PromiseReactions для выполнения и отклонения соответственно на основе promiseCapability и onfulfilled/onrejected, что является последним действием, которое должно быть выполнено в PromiseJobs. Если текущее обещание (this) находится в состоянии ожидания, вставьте эти две реакции в промис соответственно[[PromiseFulfillReactions]]а также[[PromiseRejectReactions]]в очереди. Но если в это время обещание уже выполнено или отвергнуто, то из[[PromiseResult]]Выньте результат значения и вставьте его в очередь заданий как причину выполненного результата/отклонения.EnqueueJob("PromiseJobs", PromiseReactionJob, <<reaciton, result>>)и, наконец, возвращает новое обещание, хранящееся в prjomiseCapability.Promise.prototype.catch(onrejected)то естьPromise.prototype.then(undefined, onrejected)

Promise.resolve(x)

создай такой как тогдаpromiseCapability, а затем напрямую вызватьresolve functionИ передайте значение x для разрешения и, наконец, верните в нем новое обещание.

Promise.all(iterable)

Promise.all также создает тогда как тогдаpromiseCapability, который содержит новое обещание и связанное с нимresolve functionа такжеreject function, а затем объедините цикл итератора: 1. Если итерация закончилась, а счетчик равен 0, вызовитеpromiseCapabilityизresolve functionдля разрешения результирующего массива 2. В противном случае счетчик увеличивается на 1, а затем значение следующей итерации берется и передается вPromise.resolveтакже создает новое обещание, а затем внутренне создаетPromise.all Resolve Element Function, переданный этому новому промису, затем добавить результат в массив результатов и уменьшить счетчик на единицу.

Promise.race(iterable)

Таким же образом создайтеpromiseCapability, а затем повторите сPromise.resolveчтобы создать новое обещание, затем вызовите метод then нового обещания, передав promiseCapabilityresolve/reject function, в сочетании с обещанием, которое упоминалось ранее, разрешается только один раз, вы можете видеть, что это действительно означает расу.

Эпилог

Увидев это, я задаюсь вопросом, у всех ли есть более глубокое понимание Promise. Идя дальше, новый async/await, предложенный в ES6, на самом деле применяет идею генератора и промиса, Если вам интересно, вы можете продолжить изучение этого.


Текст / Какся

без введения автора

Автор разрешил опубликовать эту статью, и авторские права принадлежат Chuangyu Frontend. Пожалуйста, укажите источник для перепечатки этой статьи. Ссылка на эту статью:известно Sec-Fed.com/2018-08-22-…

Если вы хотите увидеть больше сообщений с передовой линии KnownsecFED, выполните поиск и подпишитесь на нашу общедоступную учетную запись WeChat: KnownsecFED. Добро пожаловать, чтобы оставить сообщение для обсуждения, мы ответим как можно скорее.

Спасибо за прочтение.