Я также нашел простое, более простое решение. То есть с помощью атрибута screen.width и проверки диапазона ширины, а затем сброса атрибутов метатега viewport. он выглядел бы примерно так:
Это происходит потому, что в вашем рабочем процессе нет ничего асинхронного, когда закомментировано Sleep
.
Все полностью синхронно, но поскольку оно закодировано в вычислительном выражении async
, оно становится странным образом вложенным. Видите, каждая строка let!
фактически вызывает все, что находится справа (в вашем примере - workAsync
), и передает ей обратный вызов, который должен быть вызван после выполнения асинхронной части. Обратный вызов содержит остальную часть кода - продолжение, начинающееся сразу после строки let!
. Компилятор выполняет умные преобразования в коде, чтобы он выглядел все красиво и линейно, тогда как на самом деле это серия обратных вызовов.
Однако, поскольку workAsync
на самом деле не асинхронный, он просто сразу вызывает обратный вызов, и обратный вызов поворачивается и вызывает следующую итерацию workAsync
, и так далее. И поэтому ваш стек растет.
workAsync
, также называемом «хвостовым вызовом», и и .NETCore, и .NET Framework их устраняют (и действительно: на моей машине я не могу воспроизвести ваш результат). Единственное предположение, которое я могу предложить, это то, что вы должны запустить это на Mono, что не всегда устраняет хвостовые вызовы.
Однако, если вы раскомментируете Sleep
, это становится переломным моментом. Sleep
является на самом деле асинхронным, что означает, что он планирует выполнение обратного вызова в новом потоке после истечения времени ожидания. Это выполнение начинается с нуля, со свежим стеком, и поэтому стек не растет, даже если хвостовые вызовы не исключены.
Итак, чтобы ответить на ваш первоначальный вопрос: нет, бесконечное асинхронное вычисление не может переполнить стек, кроме случаев, когда оно фактически не асинхронно и выполняется в Mono.