有没有办法检查脚本是否在 dart vm 或 dart2js 中运行?也许使用镜像 API?
7 回答
据我所知,没有官方的方法。其目的是出于所有实际目的,您不必知道您是在运行本机还是编译为 JavaScript。
也就是说,您可以使用的技巧很少。最简单的可能是利用了 Dart 有两种数字类型int
和double
,而 JavaScript 只有一种,相当于 Dart 的double
,而 dart2js 还没有特殊的实现int
。因此,identical(1, 1.0)
在false
Dart 中,VM 正确地实现了它,但是当编译为 JS 时,它是true
.
请注意,在使用这样的 hack 之前,您应该好好思考一下。在大多数情况下,您不必这样做,只需编写 Dart 并且不要尝试识别您是否在运行 JS。此外,没有人能保证它会永远有效。
基于在路径库(Dart v0.7.2) 中找到的代码片段:
import 'dart:mirrors';
/// Value indicating that the VM is Dart on server-side.
const int DART_SERVER=1;
/// Value indicating that the VM is Dart on client-side.
const int DART_CLIENT=2;
/// Value indicating that the VM is JavaScript on client-side (e.g. dart2js).
const int JS_CLIENT=3;
/// Returns the type of the current virtual machine.
int vmType() {
Map<Uri, LibraryMirror> libraries=currentMirrorSystem().libraries;
if(libraries[Uri.parse('dart:io')]!=null) return DART_SERVER;
if(libraries[Uri.parse('dart:html')]!=null) return DART_CLIENT;
return JS_CLIENT;
}
/// Application entry point.
void main() {
print(vmType());
}
让脚本判断是在服务器端 VM 还是在客户端运行的另一种非常老套的方法是使用Options
该类。
以下应用程序(名为 的文件myapp.dart
)在命令行 VM 或浏览器中运行时会打印不同的输出:
void main() {
var options = new Options();
print(options.arguments);
print(options.executable);
print(options.script);
}
命令行输出:
[]
C:\work\dart\editor\dart\dart-sdk\bin\dart.exe
myapp.dart
浏览器内输出:
[]
<-- empty string
<-- empty string
不过,无论是在 Dart 浏览器 VM 中运行还是作为 JS 运行,浏览器内的输出都是相同的。
由于 dart.js 将脚本 .dart 转换为 .dart.js,因此可以:
bool _isDart() => document.getElementsByTagName("script").where((s) => s.src.endsWith(".dart.js")).isEmpty;
我一直在考虑这个问题,实际上,有一种方法可以发现浏览器是否支持使用navigator.webkitStartDart
. 这是引导 Dart 使用的 dart.js 文件,在确定浏览器是否原生支持 dart 时,我们可以使用 JavaScript 互操作来做同样的事情。
true
如果在Dartium中运行,但false
如果在Chrome或Firefox中运行,则以下应用程序返回:
import 'dart:html';
import 'package:js/js.dart' as js;
void main() {
print("Is Dart? = ${isDart()}");
}
bool isDart() => js.scoped(() {
try {
// will throw exception if it doesn't exist
var dartExists = js.context.navigator.webkitStartDart;
return true;
}
on NoSuchMethodError {
return false;
}
});
您的 pubspec 将需要如下所示:
name: webkitstart
description: A sample web application
dependencies:
browser: any
js: any
@Ladicek 对另一个答案的警告仍然有效:
在大多数情况下,您不必这样做,只需编写 Dart 并且不要尝试识别您是否正在运行 JS。
更新- 这个解决方案实际上并没有告诉脚本是否在基于浏览器的 dartvm 中运行,只是 dartvm 在浏览器中可用。但是,如果您使用包括packages/browser/dart.js
- 在内的标准脚本标签部署您的应用程序,那么这将确保如果浏览器具有dart-vm,它将在 dart-vm 中启动应用程序。如果您仅显式链接应用程序的 .dart.js 版本并删除对 dart.js 脚本的引用,您只会让应用程序在 javascript 中运行
即,这:
<!-- will use dart-vm if available, fallback to JS if not -->
<script type="application/dart" src="example.dart"></script>
<script src="packages/browser/dart.js"></script>
与此相比:
<!-- will only use JS, even if dart vm is available -->
<script type="application/dart" src="example.dart.js"></script>
我不建议您尝试弄清楚您是在“在 VM 上”运行还是编译为 JavaScript。未来,运行 Dart 的方法可能不止这些。
您应该检测您实际想要使用的功能。
要检查 JavaScript集成是否可用,您可以检查它是否可用const bool.fromEnvironment("dart.library.js")
。这意味着该dart:js
库可用。您可以使用条件导入来导入仅取决于dart:js
可用时的库:
import "feature_default.dart"
if (dart.library.js) import "feature_js.dart";
feature_js.dart
仅当库可用时才会导入dart:js
,否则将导入feature_default.dart
. (这两个库应该足够相似,无论导入哪个库,导入库都是正确的)。
目前有许多库仅在浏览器中运行时可用:dart:js
以及dart:html
其他 DOM 库。同样,目前只有 VM 具有dart:cli
和dart:ffi
。这些库dart:mirror
仅在某些VM 上可用(它不在 Flutter 中,也不在提前编译的代码中)。
当前的组合没有任何内在的东西。可以将 Dart 和 VM 编译为 WASM,然后在浏览器中运行它并使其dart:js
可用于集成。或者构建一个基于 VM 的应用程序,该应用程序嵌入浏览器视图并dart:html
在 VM 上运行时仍可使用。
这就是为什么你应该测试你需要的库的可用性,而不是试图从中推断出一个“平台”。平台是开放式的,如果不假设只有两个平台,您的代码将是面向未来的(尽可能多的事情是可能的)。
对于整数,您只需通过对它们进行操作来检查它们是 64 位整数还是浮点数。例如bool integersAreFloats = (9007199254740992 == (9007199254740992 + 1));
我认为现在最好的方法是:https ://dart.dev/guides/libraries/create-library-packages#conditionally-importing-and-exporting-library-files (stackoverflow上的示例)。
规范:https ://github.com/munificent/dep-interface-libraries/blob/master/Proposal.md
我认为它是依赖于实现的黑客:
const _isJs = (1 << 32) == 0 || (1 << 32) == 1;
dartpad 上的示例:这里。
表达式的第一部分依赖于dart2js
(见#1,#2)的当前实现。
表达式的第二部分依赖于 JS 规范:MDN。
console.log(1 << 32); // 1