【问题标题】:How do I load a WASM module in a Vue component without initializing the module every time?如何在 Vue 组件中加载 WASM 模块而不每次都初始化模块?
【发布时间】:2018-07-21 23:42:24
【问题描述】:

我使用

创建了一个 cdylib 类型的 Rust 库
cargo web build --target=wasm32-unknown-unknown

我使用“rust-wasm-loader”NPM 包的修改版本来构建和加载 WASM 文件。 rust-wasm-loader 以此作为使用 Rust 代码的一种方式:

const wasm = require('./main.rs')
wasm.initialize().then(module => {
    // Use your module here 
    const doub = module.cwrap('doub', 'number', ['number'])
    console.log(doub(21))
})

我不想每次使用代码时都初始化模块。如何加载模块并像库一样使用它?

【问题讨论】:

  • 你可以捕获对模块的引用作为全局变量吗?你不需要任何复杂的东西,因为它是 WebAssembly
  • 如果在加载/初始化 WebAssembly 模块之前使用组件时,您希望组件的行为是什么?我认为该解决方案将与您为支持代码拆分/异步组件所做的相同。我不了解 Vue,但我在 React 中使用过类似的技术。我支持“它并不特别,因为它是 WebAssembly”这一点。

标签: ecmascript-6 vue.js rust webassembly


【解决方案1】:

由于 WebAssembly 的加载是异步的,对于大型模块实际上可能需要一些时间,因此您需要处理模块未加载时的状态,然后让应用程序的其余部分知道 WebAssembly 模块何时加载。

你没有说你是如何在你的 Vue 应用程序中处理状态的,但是如果你是例如使用 Vuex 你可以做这样的事情:

const doubPlugin = store => {
  wasm.initialize().then(module => {
    const doub = module.cwrap('doub', 'number', ['number'])

    store.subscribe((mutation, state) => {
      if (mutation.type === 'DOUB_REQUEST') {
        store.commit('DOUB_RESULT', doub(mutation.payload))
      }
    })

    store.commit('DOUB_READY')
  })
}

const store = new Vuex.Store({
  state,
  mutations,
  plugins: [doubPlugin]
})

我在 Elm/WebAssembly 应用程序 (relevant JavaScript) 中做了类似的事情,所以如果你想看看如何在实践中应用它,你可以看看。

【讨论】:

    【解决方案2】:

    制作一个执行初始化并重新导出承诺的包装 JS 模块似乎是最直接的方法。

    // main.js
    module.exports = require("./main.rs").initialize().then(module => {
      return {
        doub: module.cwrap('doub', 'number', ['number'])
      };
    });
    

    然后什么都可以做

    require("./main.js").then(api => {
      console.log(api.doub(21));
    });
    

    并且总是会得到相同的模块。或者,您可以反转异步部分并执行

    // main.js
    const api = require("./main.rs").initialize().then(module => {
      return {
        doub: module.cwrap('doub', 'number', ['number'])
      };
    });
    
    exports.doub = async function (val) {
      return (await api).doub(val);
    };
    

    然后你的模块的用户可以做

    const api = require("./main.js");
    api.doub(21).then(result => {
      console.log(result);
    });
    

    【讨论】:

    • 我正在使用您的第一个示例。结果是一个完整的承诺。我仍然需要添加一个 .then(api => {})。有没有办法只调用 api.doub(2)?
    • 如果你愿意,但它需要一个单独的侧通道来确保模块首先加载。从 API 级别来看,这不是一个理想的设计。我认为您使用方法 1 并对其进行缓存的方法对于您想要的东西来说是一种很好的方法,只要您确定它在您需要的时候就存在。
    【解决方案3】:

    我创建了一个类来包装 WebAssembly 加载并为每个函数创建一个 cwrap:

    class mkLib {
      ready = false
      _mod = require("./main.rs").initialize().then(module => {
        this._mod = module
        this.doub = module.cwrap('doub', 'number', ['number'])
        this.ready = true
      })
    
    }
    export default mkLib
    

    在 Vue 组件的 data 中有一个新类的变量,在 watch 中,我等待 ready 属性的更改:

    data () {
      return {
        mod: new mkLib,
        ready: false
      }
    },
    watch: {
      'mod.ready': function () {
        this.ready = true
        // now this.mod.FUNC(PARAMS) can be used
        console.log(this.mod.doub(20))
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-05-09
      • 2020-07-18
      • 2021-04-06
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 2019-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多