Рабочие места для обработки обещания переходят в «очередь заданий на обещание» (PJQ), описанную в стандартах ECMAScript.Эта номенклатура не часто используется в документации HTML.
Браузеры (и, по крайней мере, один механизм сценариев) помещают задания для PJQ в то, что обычно называют «Микро-очередь задач» (MTQ).Диспетчер задач цикла событий проверяет MTQ при возврате из вызова сценария из цикла событий, чтобы определить, есть ли в нем какие-либо задания, и выскочит и выполнит самое старое задание в очереди, если оно есть.Строка в исходном сообщении
while(!(await callbackCalled)) null;
(что при первом вызове эквивалентно
while( !( await Promise.resolve( false)); // callbackCalled is false
)
помещает задание для получения установленного значенияобещание, возвращаемое Promise.resolve в MTQ и продолжающее выполнение, когда оператор await
возвращает выполненное значение, равное false
.
, поскольку браузеры обрабатывают MTQ с более высоким приоритетом, чем задачи, сгенерированныеистечение таймера, выполнение продолжается после операции await
и немедленно выполняет еще одну итерацию цикла и помещает другое задание в MTQ для ожидания значения false
, без обработки каких-либо обратных вызовов таймера между .
Это устанавливает асинхронный бесконечный цикл (кстати, поздравляю, я такого еще не видел!), И в этих условиях я бы не ожидал, что обратный вызов таймера будет выполнен и вызовет timeoutLoopCallback
во второй раз.
Бесконечный цикл также блокирует продолжение следующей строки:
foo.stop()
никогда не выполняется.
Обратите внимание на блокиНаблюдаемый здесь эффект является следствием реализации «Обещания заданий» в HTML-коде. Принятый ECMAScript решил не указывать детали реализации и приоритета для реальных систем JavaScript.Так что вините стандарты HTML, а не ECMAScript: D
Также обратите внимание: замена await calledBackCalled
на await hasCallbackCalled()
не решит проблему - будут сгенерированы разные задания обещания, но оператор await по-прежнему вернет false
.
(обновление) Поскольку вы спрашиваете, фактические шаги для
while(!(await hasCallbackCalled())) null;
:
- Оценка
hasCallbackCalled()
- 'hasCallbackCalled` является асинхроннымФункция и возвращает обещание, выполненное с возвращаемым значением тела функции.
- Тело функции является синхронным кодом и выполняет возвращенное обещание при первом вызове, синхронно возвращая значение
callbackCalled
(что составляет false
) - Обещание, возвращаемое асинхронной функцией, до сих пор синхронно выполнялось со значением
false
. await
теперь добавляет обработчики, вызывая .then
для обещания, полученного вшаг 4, чтобы сообщить await
установленное значение и состояние (в данном случае «выполнено»). - Но вызов
then
для выполненного обещания синхронно вставляет задание для вызова обработчика с выполненным значением в MTQ - у MTQ теперь есть задание длякод вызова для этого конкретного
await
назад; await
возвращается в диспетчер цикла событий. - теперь задание MTQ выполняет обработчик then, добавленный на шаге 5,
- обработчик then возобновляет обработку оператора
await
который возвращает значение false
пользовательскому сценарию. - пока цикл цикла продолжится с шага 1.