Первое обновление:
Сначала я подумал, .catch( callback)
после того, как 'main' вернет новое ожидающее обещание расширенного класса Promise, но это неверно - вызов асинхронной функции возвращает обещание Promise
.
Сокращение кода, чтобы получить только ожидающее обещание:
class CancellablePromise extends Promise {
constructor(executor) {
console.log("CancellablePromise::constructor");
super(executor);
}
}
async function test() {
await new CancellablePromise( ()=>null);
}
test();
показывает, что расширенный конструктор вызывается дважды в Firefox, Chrome и Node.
Теперь await
вызывает Promise.resolve
для своего операнда. (Правка: или, возможно, это было в ранних версиях Jyn Engine async / await, которые не были строго реализованы в стандарте)
Если операнд является обещанием, конструктор которого - Promise, Promise.resolve
возвращает операнд без изменений.
Если операнд является доступным, конструктор которого не является Promise
, Promise.resolve
вызывает метод then операнда с обработчиками как onfulfilled, так и onRejected, чтобы получить уведомление об установившемся состоянии операнда. Обещание, созданное и возвращаемое этим вызовом then
, относится к расширенному классу и учитывает второй вызов CancellablePromise.prototype.constructor.
Подтверждающие доказательства
new CancellablePromise().constructor
is CancellablePromise
class CancellablePromise extends Promise {
constructor(executor) {
super(executor);
}
}
console.log ( new CancellablePromise( ()=>null).constructor.name);
- Изменение
CancellablePromise.prototype.constructor
на Promise
для целей тестирования вызывает только один вызов CancellablePromise
(потому что await
одурачен для возврата своего операнда):
class CancellablePromise extends Promise {
constructor(executor) {
console.log("CancellablePromise::constructor");
super(executor);
}
}
CancellablePromise.prototype.constructor = Promise; // TESTING ONLY
async function test() {
await new CancellablePromise( ()=>null);
}
test();
Второе обновление (огромное спасибо ссылкам, предоставленным ОП)
Соответствующие реализации
Согласно спецификации await
await
создает анонимное промежуточное Promise обещание с обработчиками onFulilled и onRejected для обоих
возобновите выполнение после оператора await
или сгенерируйте из него ошибку, в зависимости от того, в каком установленном состоянии выполняется промежуточное обещание.
Он (await
) также вызывает then
в обещании операнда выполнить или отклонить промежуточное обещание. Этот конкретный вызов then
возвращает обещание класса operandPromise.constructor
. Хотя возвращаемое обещание then
никогда не используется, регистрация в конструкторе расширенного класса выявляет вызов.
Если значение расширенного обещания constructor
будет изменено на Promise
для экспериментальных целей, вышеуказанный вызов then
будет без вывода сообщений вернуть обещание класса Promise.
Приложение: Расшифровка спецификации await
Пусть asyncContext будет текущим контекстом выполнения.
Пусть обещание будет! NewPromiseCapability (% Promise%).
Создает новый jQuery-подобный отложенный объект со свойствами promise
, resolve
и reject
, называя его «Запись PromiseCapability». Объект promise
объекта deferred имеет базовый класс Promise .
- Выполнить! Call (обещание возможности. [[Resolve]], не определено, «обещание»).
Разрешите отложенное обещание с правильным операндом await
. Процесс разрешения либо вызывает метод операнда then
, если он является «тогда доступным», либо выполняет отложенное обещание, если операндом является какое-то другое значение, не являющееся обещанием.
Пусть stepsFulfilled - шаги алгоритма, определенные в Await Fulfilled Functions.
Пусть onFulfilled будет функцией CreateBuiltin (stepsFulfilled, «[[AsyncContext]]»).
Установить onFulfilled. [[AsyncContext]] в asyncContext.
Создайте обработчик onfulfilled для возобновления операции await
внутри функции async
, в которую она была вызвана, возвращая выполненное значение операнда, переданного обработчику в качестве аргумента.
Пусть stepsRejected - шаги алгоритма, определенные в Await Rejected Functions.
Пусть onRejected будет CreateBuiltinFunction (stepsRejected, «[[AsyncContext]]»).
Установить для OnRejected. [[AsyncContext]] значение asyncContext.
Создайте отвергнутый обработчик для возобновления операции await
внутри функции async
, в которую она была вызвана, путем выдачи причины отклонения обещания, переданной обработчику в качестве аргумента.
- Выполнить! PerformPromiseThen (обещание возможности. [[Promise]], onFulfilled, onRejected).
Вызовите then
по отложенному обещанию с этими двумя обработчиками, чтобы await
мог ответить на установление своего операнда.
Этот вызов, использующий три параметра, является оптимизацией, которая фактически означает, что then
был вызван внутри и не будет создавать или возвращать обещание из вызова. Следовательно, урегулирование отложенного будет отправлять вызов одного из его обработчиков расчета в очередь заданий на выполнение, но не имеет дополнительных побочных эффектов.
Удалите asyncContext из стека контекста исполнения и восстановите контекст исполнения, находящийся на вершине стека контекста исполнения, в качестве запущенного контекста исполнения.
Установите состояние оценки кода asyncContext таким образом, чтобы при возобновлении оценки с завершением завершения были выполнены следующие шаги алгоритма, вызвавшего Await, с доступным завершением.
Сохранение места возобновления после успешного выполнения await
и возврата к циклу событий или диспетчеру очередей микрозадач.