Исключение, когда javascript ожидает асинхронную функцию Dart

#javascript #dart #web #async-await

Вопрос:

У меня есть веб-приложение, для которого я реализую API, который может использоваться независимыми сценариями js. Используя рекомендуемый пакет:js/js.dart с аннотациями @JS, все вызовы из js в Dart работают нормально, за исключением асинхронных вызовов для ожидания функции Dart. Вызов ожидания вызывает исключение или не ожидает.

Я написал небольшой пример проекта VSCode, который легко воспроизводит проблему.

Асинхронная функция Dart connect возвращает будущее, но когда будущее завершено, возникает исключение. Связано ли это с тем, что Dart возвращает будущее, но javascript ожидает обещания?

Есть много сообщений, ссылающихся на вызовы Dart в javascript, но я нашел очень мало в обратном направлении (от js к Dart) с использованием async/await. Я ожидал, что функции promiseToFuture и futureToPromise, возможно, прольют некоторый свет на эту проблему, но в контексте js-to-dart не так много информации. Документация Dart по этому вопросу, похоже, отсутствует.

Есть еще одна странная проблема, которая может быть просто симптомом. При использовании ‘webdev serve’ вызов ожидания вызывает исключение, но, если он пойман при попытке/перехвате, ожидание действительно ожидает и возвращает значение завершения. Используя «сборку webdev», вызовы ожидания вообще не ждут.

Если я пропустил соответствующую документацию, я был бы очень признателен, если бы мне указали правильное направление. Кроме того, я хотел бы услышать любые предложения по рабочему решению!

Весь код Dart находится в main.dart, построен и протестирован на:

Dart SDK 2.14.4 (стабильный) (Ср Окт 13 11:11:32 2021 0200) на «windows_x64»: VS Код 1.62.3 (настройка пользователя) ОС: Windows 10 (Windows_NT x64 10.0.19043) Chrome 96.0.4664.45 (Официальная сборка) (64-разрядная версия)

 @JS() library testawait;  import 'dart:async'; import 'dart:core'; import 'package:js/js.dart';  /// main.dart /// /// This web app is an example of a javascript script await-ing a Dart async /// function. The Dart async function returns a Future but when the future  /// is completed an exception is thrown. Is this to do with Dart returning /// a Future but the javascript expecting a Promise? ///  /// The script is triggered by a button (Click me) in the web page (index.html). /// /// When running with WEBDEV SERVE the awaits respect the Future.delays but throw /// exceptions and the returns go to the catch. ///  /// When running with WEBDEV BUILD the awaits do not delay and the returns go to /// the next statement.  @JS('connect') external set _connect(void Function(String host) f);  void main() async {  _connect = allowInterop(connect); }  /// /// This causes an exception but the await does wait and the  /// completion is returned to the catch (with webdev serve): ///  /// Uncaught TypeError: T.as is not a function /// at _Future.new.[_setValue] (future_impl.dart:419) /// Futurelt;dynamicgt; connect(String host) async {  print('main: before connect');  var completer = Completerlt;dynamicgt;();   // This is just to simulate a connect event being processed  // elsewhere that completes the completer. This future  // is not used for anything else.  Future.delayed(Duration(seconds:2), () {  print('main: connect done after 3s');  completer.complete('Future: Connect complete');  });   return completer.future; }  

And here is the html that includes the js script; click on the ‘click me’ button to trigger a call to scriptWaits:

 lt;!DOCTYPE htmlgt; lt;htmlgt; lt;headgt;  lt;meta charset="utf-8"gt;  lt;meta http-equiv="X-UA-Compatible" content="IE=edge"gt;  lt;meta name="viewport" content="width=device-width, initial-scale=1.0"gt;  lt;meta name="scaffolded-by" content="https://github.com/dart-lang/sdk"gt;  lt;titlegt;testawaitlt;/titlegt;  lt;script defer src="main.dart.js"gt;lt;/scriptgt; lt;stylegt; html, body {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  font-family: 'Roboto', sans-serif; }  #trigger-div {  height: 100%;  display: flex;  justify-content: center;  align-items: center; }  #trigger-round {  padding: 40px;  border-radius: 50%;  background-color: darksalmon; } lt;/stylegt; lt;/headgt;  lt;bodygt;  lt;div id='trigger-div'gt;  lt;div id='trigger-round'gt;  lt;input type="button" value="Click me" id="script_trigger" onclick="scriptWaits()"gt;lt;/inputgt;  lt;/divgt;  lt;/divgt;  lt;pgt;open developer tools console to see resultslt;/pgt;   lt;scriptgt;  async function scriptWaits() {  var reply = '';   console.log('Script: before calling connect');  try {  reply = await connect('host');  console.log('Script: after calling connect, reply='   reply);  } catch(e) {  reply = e;  console.log('Script: catch connect wait, '   reply);   }  }  lt;/scriptgt; lt;/bodygt; lt;/htmlgt;  

and pubspec.yaml:

 name: testawait description: Testing javascript await a Dart function version: 1.0.0  environment:  sdk: 'gt;=2.14.4 lt;3.0.0'  dependencies:  http: ^0.13.3  dev_dependencies:  build_runner: ^2.1.2  build_web_compilers: ^3.2.1  js: ^0.6.3  lints: ^1.0.0