【发布时间】:2022-07-06 05:04:22
【问题描述】:
我有一个 Web 应用程序,我正在为其实现一个可供独立 js 脚本使用的 API。使用推荐的包:js/js.dart 和 @JS 注释,从 js 到 Dart 的调用都可以正常工作,除了对 Dart 函数的异步调用 await。 await 调用抛出异常或不等待。
我已经编写了一个小示例 VScode 项目,可以轻松重现该问题。
Dart connect 异步函数返回一个 Future,但是当 Future 完成时会抛出异常。这是否与 Dart 返回 Future 但 javascript 期望 Promise 有关?
有很多帖子引用了 javascript 中的 Dart 调用,但我发现使用 async/await 的反向方向(js 到 Dart)很少。我预计 promiseToFuture 和 futureToPromise 函数可能会对这个问题有所启发,但在 js-to-dart 上下文中没有太多信息。关于这个问题的 Dart 文档似乎不存在。
还有一个奇怪的问题可能只是一个症状。使用“webdev serve”,await 调用会抛出异常,但如果它在 try/catch 中被捕获,则 awaits 实际上会等待并返回完成值。使用“webdev build”,等待调用根本不等待。
如果我错过了相关文档,我将非常感谢您指出正确的方向。除此之外,我想听听有关可行解决方案的任何建议!
所有 Dart 代码都在 main.dart 中,构建和测试在:
Dart SDK 2.14.4(稳定版)(2021 年 10 月 13 日星期三 11:11:32 2021 +0200)在“windows_x64”上: VS Code 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)
///
Future<dynamic> connect(String host) async {
print('main: before connect');
var completer = Completer<dynamic>();
// 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;
}
这里是包含 js 脚本的 html;单击“单击我”按钮以触发对 scriptWaits 的调用:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="scaffolded-by" content="https://github.com/dart-lang/sdk">
<title>testawait</title>
<script defer src="main.dart.js"></script>
<style>
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;
}
</style>
</head>
<body>
<div id='trigger-div'>
<div id='trigger-round'>
<input type="button" value="Click me" id="script_trigger" onclick="scriptWaits()"></input>
</div>
</div>
<p>open developer tools console to see results</p>
<script>
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);
}
}
</script>
</body>
</html>
和 pubspec.yaml:
name: testawait
description: Testing javascript await a Dart function
version: 1.0.0
environment:
sdk: '>=2.14.4 <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
【问题讨论】:
标签: javascript dart web async-await