> new Promise((resolve, reject) => setTimeout(resolve, 1000, 'foo'))
> .then(console.log)
> // foo (1s后)
При использовании Promise наше самое простое понимание и использование состоит в том, чтобы предоставить асинхронный результат для разрешения в качестве параметра, подобного приведенному выше коду, а затем передать пользовательскую функцию методу then в качестве функции обработки результата. Но что такое параметры разрешения и отклонения? Каков основной способ работы за этим? Давайте сначала посмотрим на это с нормативной точки зрения.
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
Точно так же, когда он генерируется, он связан с обещанием. Во время выполнения параметр, который мы передаем, называется разрешением. Возвращает неопределенное значение, если обещание разрешено. После этого ситуация усложняется.
- Если пользователь передает само обещание в функцию разрешения в качестве разрешения параметра, будет создана ошибка TypeError, выброшена и вызвана
RejectPromise
, параметр Reason — это TypeError. - Если тип разрешения не Object, вызовите
FulfillPromise(promise, resolution)
. - Остальные случаи случаев, когда разрешение является объектом с тогдашним (обещанием), кроме самого себя.
- Если разрешение — это объект без then, то
RejectPromise
. - Если есть атрибут then, но его нельзя вызвать, также
FulfillPromise
, . - Если есть атрибут then и его можно вызвать, то
EnqueueJob("PromiseJobs", PromiseResolveThenableJob, <<promise, resolution, thenAction>>)
.
- Если разрешение — это объект без then, то
в описанииEnqueueJob
Прежде взгляните на то, что такое Иов. Проще говоря, это как внутри механизма обратного вызова добиться: «Когда нет других запущенных ES, инициализировать и выполнить свой собственный соответствующий ES». В очереди FIFO задания у нас есть ожидающее выполнение, и текущая среда выполнения, в которой запущен контекст выполнения и стек контекста выполнения, когда последние два пусты, будет выполняться первой очередью заданий.
ES предусматривает, что в реализации должно быть не менее двух очередей заданий,ScriptJobs
а такжеPromiseJobs
. когда мы звонимEnqueueJob("PromiseJobs", ...)
, задания, которые необходимо выполнить, и их параметры вставляются вPromiseJobs
эта очередь. Как вы можете видеть, есть два вида Jobs под Promise.
-
PromiseReactionJob(reaction, argument)
реакция имеет три внутренних слота[[Capability]]
,[[Type]]
а также[[Handler]]
,Соответственно[[关联的 promise 及相关的resolve function 和 reject function]]
,[[类别]]
,[[handler]]
. Если пользователь не указывает handler(undefined), в качестве результата используется аргумент в зависимости от того, является ли категория «Выполнить» или «Отклонить». Если указан обработчик, используйте его для дальнейшей обработки аргумента. Наконец, в соответствии с этим результатом, для обработки и возврата используются функция разрешения и функция отклонения. -
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. Добро пожаловать, чтобы оставить сообщение для обсуждения, мы ответим как можно скорее.
Спасибо за прочтение.