Проблема, которую вы описываете, двоякая.
- Программа, которую вы пишете, должна вести себя асинхронно в целом, если смотреть на нее снаружи .
- На месте вызова не должно быть видно, может ли вызов функции отказаться от управления или нет.
Есть несколько способов добиться этого, но они в основном сводятся к
- иметь несколько потоков (на некотором уровне абстракции)
- иметь несколько видов функций на уровне языка, и все они называются так
foo(4, 7, bar, quux)
.
Для (1) я собираю вместе ветвление и запуск нескольких процессов, порождаем несколько потоков ядра и реализации зеленых потоков, которые планируют потоки уровня времени выполнения для потоков ядра. С точки зрения проблемы они одинаковы. В этом мире ни одна функция никогда не сдается и не теряет контроль с точки зрения своего потока . Сам поток иногда не имеет контроля, а иногда не работает, но вы не отказываетесь от контроля над собственным потоком в этом мире. Система, подходящая для этой модели, может иметь или не иметь возможность создавать новые потоки или присоединяться к существующим. Система, подходящая для этой модели, может иметь или не иметь возможность дублировать поток, как в Unixfork
.
(2) интересно. Чтобы сделать это справедливо, нам нужно поговорить о формах введения и устранения.
Я собираюсь показать, почему неявное await
не может быть добавлено к языку, подобному Javascript, обратно совместимым способом. Основная идея заключается в том, что, предоставляя пользователю обещания и различая синхронный и асинхронный контексты, в Javascript просочилась деталь реализации, которая препятствует равномерной обработке синхронных и асинхронных функций. Также существует тот факт, что вы не можете await
обещать вне тела асинхронной функции. Эти варианты дизайна несовместимы с «сделать асинхронность невидимой для вызывающего».
Вы можете ввести синхронную функцию с помощью лямбда-выражения и устранить ее с помощью вызова функции.
Синхронное введение функции:
((x) => {return x + x;})
Синхронное исключение функций:
f(4)
((x) => {return x + x;})(4)
Вы можете противопоставить это введению и устранению асинхронных функций.
Внедрение асинхронной функции
(async (x) => {return x + x;})
Устранение асинхронной функции (примечание: действует только внутри async
функции)
await (async (x) => {return x + x;})(4)
Основная проблема здесь заключается в том, что асинхронная функция также является синхронной функцией, создающей объект обещания .
Вот пример вызова асинхронной функции синхронно в repl node.js.
> (async (x) => {return x + x;})(4)
Promise { 8 }
Вы можете гипотетически иметь язык, даже динамически типизированный, где разница между асинхронными и синхронными вызовами функций не видна на сайте вызовов и, возможно, не видна на сайте определения.
Взяв такой язык и опуская его до Javascript, можно просто сделать все функции асинхронными.