Vue项目中导入Wasm学习记录

webassembly官网如下

网站组装 (webassembly.org)

下面是官网对wasm的说明:

WebAssembly(缩写为Wasm)是基于堆栈的虚拟机的二进制指令格式。Wasm被设计为编程语言的可移植编译目标,支持在Web上部署客户端和服务器应用程序。

  1. Wasm堆栈计算机设计为以大小和加载时间高效的二进制格式进行编码。WebAssembly旨在通过利用各种平台上可用的通用硬件功能,以本机速度执行。
  2. WebAssembly被设计为以文本格式精美打印,用于调试,测试,实验,优化,学习,教学和手动编写程序。在网络上查看 Wasm 模块的源代码时将使用文本格式。
  3. WebAssembly 描述了一个内存安全的沙盒执行环境,甚至可以在现有的 JavaScript 虚拟机中实现。当嵌入到 Web 中时,WebAssembly 将强制执行浏览器的同源和权限安全策略。
  4. WebAssembly 旨在维护 Web 的无版本、功能测试和向后兼容的性质。WebAssembly 模块将能够调用进出 JavaScript 上下文,并通过可从 JavaScript 访问的相同 Web API 访问浏览器功能。WebAssembly 还支持非 Web 嵌入。

构建wasm项目

使用AssemblyScript构建wasm项目指南:Getting started | The AssemblyScript Book

以下是直接从这个网站中复制下来的

首先建立一个空文件夹,然后使用VsCode打开它,新建终端分别执行如下的命令,这里能执行node.js相关的命令,前提是安装node.js的时候记得配置系统环境变量

在这里插入图片描述

确保节点的最新版本.js (打开新窗口)并安装了它的包管理器 npm(随 Node.js 一起安装,然后切换到新目录并像往常一样初始化一个新的 Node.js 模块:

npm init

在这里插入图片描述

安装 AssemblyScript 编译器。让我们假设它在生产中不是必需的,并使其成为开发依赖项:

npm install --save-dev assemblyscript

在这里插入图片描述

安装后,编译器提供了一个方便的脚手架实用程序来快速设置新项目,位于当前目录中:而且这里注意的是,命令行中有一个英文字母的点,记得一定要写上

npx asinit .

运行命令成功之后,我们可以发现如下的目录

在这里插入图片描述

打开对应的目录文件,如下图所示,我们也可以自己写一个方法。

Concepts | The AssemblyScript Book这里有关于这个语言的语法格式要求

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eT4SNYcE-1678948730366)(Vue项目中导入Wasm学习记录.assets/image-20230316111420699.png)]

使用模块

中的示例现在可以通过调用 build 命令编译为 WebAssembly:assembly/index.ts

npm run asbuild

在这里插入图片描述

这样做会将编译的二进制文件、绑定和定义文件发出到目录中。build/

在这里插入图片描述

生成的测试用例可以使用以下命令执行:tests/index.js,测试已下是否通过

npm test

在这里插入图片描述

构建后,该目录将包含像任何其他现代节点一样使用该模块的所有位.js 环境无害管理模块:

import * as myModule from "myModule";

在这里插入图片描述

生成的模块显示了如何在 Web 上使用模块。提供 Web 服务器的服务 模块目录(默认为 display )可以通过以下方式启动:index.html``index.html

在这里插入图片描述

index.html的代码如下

<!DOCTYPE html>
<html lang="en">
<head>
<!-- <script type="module">
import { add, pringInt } from "./build/release.js";
// document.body.innerText = add(1, 2);
</script> -->
</head>
<body>
    <div id="add"></div>
    <hr>
    <div id="pringInt"></div>
    <script type="module">
        import { add, pringInt } from "./build/release.js";

        let addResult = add(1,2)
        document.getElementById("add").innerHTML = `调用assembly目录下的index.ts的add()函数
        的结果为1+2 = :${addResult}`

        let pringIntResult = pringInt(10000)
        document.getElementById("pringInt").innerHTML = `调用assembly目录下的index.ts的
        pringInt()函数的打印结果 :${pringIntResult}`
    </script>
</body>
</html>

npm start

请注意,根据用例的不同,并非所有文件都是必需的,并且它是安全的 以删除不需要的内容。如果出现任何问题,可以再次执行,这 将恢复已删除的默认文件,同时保留已编辑的文件。asinit

在这里插入图片描述

按住Ctrl+鼠标点击就可以跳到对应的网站了,或者复制网址到浏览器地址栏回车访问

在这里插入图片描述

在html中调用wasm的方法

在javascript使用wasm需要使用 WebAssembly JavaScript API实现,官网地址如下所示

使用 WebAssembly JavaScript API - WebAssembly |多核 (mozilla.org)

1、首先复制上面构建的release.wasm到对应的web项目中,release.wasm.map有没有都行,但是release.wasm要有

在这里插入图片描述
在这里插入图片描述

但是这里当我们运行的时候,f12就会发现报如下错误

Uncaught (in promise) TypeError: WebAssembly.instantiate(): Imports argument must be present and must be an object

在这里插入图片描述

这里有一个解决办法就是去我们构建wasm的项目那里,把自己写的方法的console.log注释掉,然后再重新

在这里插入图片描述

npm run asbuild

将得到的wasm复制到web项目中就可以了
在这里插入图片描述

代码如下:

<!DOCTYPE html>
<html lang="en">
<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">
    <title>Document</title>
</head>
<body>
    <div id="loadwasm" style="background-color: pink;"></div>
    <hr>
    <div id="loadwasmprint" style="background-color: pink;"></div>
    <script>
        WebAssembly.instantiateStreaming(fetch("./release.wasm")).then(
        (results) => {  
          // results?.instance?.exports这里面就有我们之前构建成wasm的两个函数add()、pringInt,具体看console.log(results.instance.exports)的结果
           //   console.log(results.instance.exports)
           console.log(results?.instance?.exports)
           var addResult = results.instance.exports.add(100,200)
           document.getElementById("loadwasm").innerHTML = `加载了使用了wasm的add()方法,100+200=:${addResult}`
           var pringIntResult = results.instance.exports.pringInt(2400)
           document.getElementById("loadwasmprint").innerHTML = `加载了使用了wasm的pringInt()方法,调用结果如:${pringIntResult}`
        })

        async  function wasm() {
            // 这是另外一种读取文件的方式
            const { instance: { exports } } = await WebAssembly.instantiateStreaming(fetch("./js/release.wasm"))
            // 这个exports就有我们之前在构建wasm文件的的两个函数add()、pringInt()
            console.log(exports)
        }
    </script>
</body>
</html>

结果如下所示,我们通过console.log(results?.instance?.exports)目前wasm中具有的函数方法

在这里插入图片描述

在Vue中调用wasm方法

在vue中读取wasm文件

在这里插入图片描述

wasm.js的代码如下


export var defaultExport = '这个是在vue中引入wasm的试验'

export async function getWasmExports() {
    const { instance: { exports } } = await WebAssembly.instantiateStreaming(fetch("./js/release.wasm"))
    // eslint-disable-next-line no-debugger
    return exports
}

export var wasmExportsObj = {}
WebAssembly.instantiateStreaming(fetch("./js/release.wasm")).then(
    (results) => {
        // eslint-disable-next-line no-debugger
        // wasmExportsObj = results.instance.exports  
        wasmExportsObj = results?.instance?.exports  
    })

export function test() {
    return 66666
}

// 这种导出方式,在引入时不需要加{},而且只能有一个export default
// 如:import defaultExport, {wasmExportsObj, test, getWasmExports} from './utils/wasm'
export default defaultExport

APP.vu的代码如下所示

<template>
  <div id="app">
    <div>在这里调用了wasm中的add()方法</div>
    <hr>
    <el-input-number v-model="num1" label="描述文字"></el-input-number>
    +
    <el-input-number v-model="num2" label="描述文字"></el-input-number>
    =
    <span style="color:blue; font-size: 24px;">{{ sum }}</span>
    <el-button type="primary" @click="sum3">计算</el-button>
    <hr>
    <el-input-number v-model="num3" label="描述文字"></el-input-number>
    +
    <el-input-number v-model="num4" label="描述文字"></el-input-number>
    =
    <span style="color:blue; font-size: 24px;">{{ sum2 }}</span>
    <el-button type="primary" @click="sum3">计算</el-button>
    <!-- <el-button type="primary" @click="sum4">计算</el-button> -->
  </div>
</template>
<script>
import defaultExport, {wasmExportsObj, test, getWasmExports} from './utils/wasm'
export default {
  name: 'APP',
  data() {
    return {
      num1: 0,
      num2: 0,
      sum: 0,
      num3: 100,
      num4: 200,
      sum2: 300
    }
  },
  methods: {
   async sum3() {
      console.log(defaultExport)
      var test2 = test()
      console.log(test2)

      // 加载调用加载wasm的方法
      let getWasmExports2 = await getWasmExports()
      console.log(`这个是wasm导出的接口对象,调用的是getWasmExports():`)
      console.log(getWasmExports2)
      console.log(getWasmExports2.add(1,2))
      this.sum = getWasmExports2?.add(this.num1,this.num2)
      
      console.log("=========================================================")
      // 调用wasm的方法2
      console.log(`这个是wasm导出的接口对象,调用的是wasmExportsObj`)
      console.log(wasmExportsObj)
      console.log(wasmExportsObj?.add(10000,30000))
      this.sum2 = wasmExportsObj.add(this.num3,this.num4)
    }
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

nav {
  padding: 30px;
}

nav a {
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
  color: #42b983;
}
</style>

npm run serve后运行的结果如下所示
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐