如何从JavaScript执行Kotlin WebAssembly函数?

时间:2019-01-10 23:05:49

标签: javascript kotlin webassembly kotlin-native kotlin-js-interop

我的目标是编写一个Kotlin库,将其编译为WebAssembly并从JS调用其功能。几个小时以来,我一直在努力建立一个简单的问候世界。有关此主题的文档不存在或隐藏得很好。

这是我的kotlin文件:

@Used
public fun hello() {
    println("Hello world!")
}

fun main(args: Array<String>) {
    println("main() function executed!")
}

当我将其编译为WebAssembly时,会得到一个 hello.wasm hello.wasm.js 文件。

首先,我尝试使用类似这样的功能来执行该功能:

WebAssembly.instantiateStreaming(fetch('hello.wasm'), importObject)
    .then(obj => obj.instance.exports.hello());

然后,我了解到我需要在 importObject 参数中传递来自 hello.wasm.js 文件的导入。所以我想我需要使用 hello.wasm.js 文件正确初始化wasm程序。

当我像下面那样加载wasm时,没有任何错误,并且执行了 main()函数。

<script wasm="hello.wasm" src="hello.wasm.js"></script>

但是如何从JavaScript执行 hello()函数?我发现的唯一Kotlin wasm示例不是调用特定函数,而是从 main()函数呈现某些内容。

非常感谢与相关文档的任何链接。


更新: 我设法执行了该函数,但我不认为这是正确的方法:

<script wasm="hello.wasm" src="hello.wasm.js"></script>
<script>
WebAssembly.instantiateStreaming(fetch('hello.wasm'), konan_dependencies)
        .then(obj => obj.instance.exports['kfun:hello$$ValueType']());
</script>

问题是,如果我这样做,我的wasm文件将被提取两次。

仅加载没有wasm属性的hello.wasm.js文件会导致以下错误:

Uncaught Error: Could not find the wasm attribute pointing to the WebAssembly binary.
    at Object.konan.moduleEntry (stats.wasm.js:433)
    at stats.wasm.js:532

3 个答案:

答案 0 :(得分:1)

最近,我本人对此进行了一些研究,据我了解,到目前为止,您的用例尚未得到真正的支持。您要找的实际上是一个库,但是如果您查看Kotlin / Native的documentation,它会指出:

  

支持以下二进制种类(请注意,并非所有种类都适用于所有本机平台):

     

[...]

     

sharedLib-共享的本机库-除wasm32之外的所有本机目标

     

staticLib-静态本机库-除wasm32外的所有本机目标

据我了解,困难在于Javascript和WebAssembly之间的数据传递,因为它仅支持int或通过线性内存的相当round回的方式。

答案 1 :(得分:0)

目前,我喜欢从事Kotlin WASM项目的工作,并且(对我的研究人员很高兴)我们的团队没有经验。抱歉,我的脑子里仍然有同样的问号,但是距离很远。

在我的案例中,我发现了wasm的许多示例,但感觉好像无法使用它们,因为在Kotlin中,情况有所不同...实际上并非如此,并且事情只是隐藏在构建过程中,我们的案子既是福也是祸。没有文档,但是科特林为我们做事!

对我来说,弥合信息空白的最佳策略是更深入地研究生成的* wasm.js文件。它看起来很恐怖,而且是JavaScript,但是实际上很容易了解Kotlin真正为您提供的功能。最好的方法:如果您查看了Api参考(https://developer.mozilla.org/en-US/docs/WebAssembly),或者只是看了一个教程,但无法应用您所看到的内容,那么最好在这里找到这些代码! >

曾经读过这篇文章并想尝试的人:您应该准备一个构建设置,该构建设置允许您将事物附加到生成的* .wasm.js文件中。在我的设置中,重要的部分:

fun addBook(book: String, numberOfBooks: Int) {
    val existingNumber = books.put(book, numberOfBooks)
    if (existingNumber != null)
        println("Book exists, BEWARE!!")
}

对该主题有多少兴趣?

答案 2 :(得分:-1)

据我所知,您需要将函数导出到变量中以继续使用它,或者留在流式处理实例中。

所以我认为应该是这样的:

auto fn = [=,*this](){
  // do things with private copies
  // all updates to persist in shared state through pointers
};
#pragma omp parallel firstprivate(fn)
fn();

之后,您可以仅将变量用作函数并像这样调用它:

let helloFunc;

WebAssembly.instantiateStreaming(fetch('hello.wasm'), importObject)
.then(({instance}) => {
helloFunc = instance.exports.hello;
});

否则,如果不需要导出函数供以后使用,则可以在实例内部使用它,如下所示:

helloFunc();

如果您不想像我一样使用对象解构,则可以继续将普通语法与obj.instance一起使用。