node.js - Vue Electron 在异步调用一些 Node 库时卡住了

标签 node.js vuejs2 electron

语境
我正在尝试使用以下堆栈构建应用程序:

  • Vue.js
  • Electron

  • 我已经开发了一段时间的简单 Vue 应用程序,并且我了解了基础知识。
    我在这里尝试做的是使用这个很棒的工具将 Vue 和 Electron 结合起来:Vue CLI Plugin Electron Builder .
    虽然我已经成功地使用这个堆栈编写了简单的应用程序,但在利用 Electron 的 nodeIntegration 时遇到了问题。这应该让 Node 直接访问我的 Vue 代码。
    问题
    我对 systeminformation 的一些方法的异步调用图书馆似乎被卡住了(有时)。
    也就是说,当我想通过调用 systeminformation 的异步方法来为我的 View 数据赋值时库,Vue 似乎无限期地挂起和等待。
    奇怪的是,有时,当我强制刷新页面时,我可以在控制台中简要地看到该方法返回数据时应该输出的日志。
    这几乎就像刷新页面强制 Vue 或其他东西更新一样。
    我怀疑以下线索,但我可能错了:
  • Vue 在我的声明和/或分配方式中的 react 性问题。
  • Node 集成问题使 Vue+Node 无法正确“绑定(bind)”。
  • Electron 对 Node 库的打包缺少要在 Vue 中使用的配置,“就好像它是一个常规的 JS 库一样”。

  • 后一点我不清楚,因为我一直使用 Electron+Vue 访问 Node 库,就像访问 Web 库一样。
    可能还有更多可能导致这些问题,但据我所知……
    重现步骤
    您可以按如下方式创建 Vue+Electron:
    vue create myapp
    vue add electron-builder
    yarn add systeminformation
    

    I'm leaving default values for Vue CLI's interactive project creation as they don't have an impact on my issue.


    根据 Vue CLI Plugin Electron Builder 关于 nodeIntegration 的文档, 我的 vue.config.js文件如下所示:
    module.exports = {
      pluginOptions: {
        electronBuilder: {
          nodeIntegration: true,
        },
      },
    };
    
    然后您可以使用 中的片段场景一 场景二 .
    方案 1
    让我们考虑以下示例,其中我使用 Axios 分配值:
    <template>
      <pre>{{ test }}</pre>
    </template>
    <script>
      import axios from "axios";
      export default {
        data() {
          return {
            test: null,
          };
        },
        async mounted() {
          console.log("Getting data from Axios...");
          // Assign a value to the "test" data with an asynchronous HTTP call with Axios.
          this.test = (
            await axios.get("https://cat-fact.herokuapp.com/facts")
          ).data;
          // It gets there as soon as the server responds.
          console.log("Got it!", this.test);
        },
      };
    </script>
    
    在这里,异步调用按预期工作,我的 test数据正确更新并在我的 View 中显示 Axios电话得到了答复。
    方案 2
    现在,如果我使用相同的逻辑从 systeminformation 的方法中获取数据图书馆:
    <template>
      <pre>{{ test }}</pre>
    </template>
    <script>
      import systeminformation from "systeminformation";
      export default {
        data() {
          return {
            test: null,
          };
        },
        async mounted() {
          console.log("Getting data from systeminformation...");
          // Assign a value to the "test" data with an asynchronous call to a method of systeminformation.
          this.test = await systeminformation.getStaticData();
          // It just won't get there most of the time...
          console.log("Got it!", this.test);
        },
      };
    </script>
    
    在这种情况下,我的 View 不会显示 test Vue 的数据似乎卡在 systeminformation无限期地打电话。
    控制台日志甚至不会显示,因为 await 语句似乎使 mounted钩子(Hook)卡住了。

    最佳答案

    我刚刚测试了systeminformation.getStaticData()在我自己的 Electron + Vue 应用程序中运行,结果如下:
    它异步执行代码,但操作非常繁重,使应用程序几乎完全没有响应。它反复产生约 30 个 Node 子进程,有效地阻塞了 3-4 个 CPU 线程。
    我认为这可能是 getStaticData() 的错误功能。您可能想在他们的仓库中创建一个新问题并报告它。
    解决方案
    要么不要使用这个特定的功能,而是通过运行其他 systeminformation 来获取所有需要的信息。职能。
    或者
    在工作人员中启用 Node 集成:

    webPreferences: {
      nodeIntegration: true,
      nodeIntegrationInWorker: true
    }
    
    在工作线程中执行此函数,而不是在主线程上,并将结果发送回您的组件,然后终止工作线程。虽然当你这样做时,打开任务管理器并确保它终止所有产生的子进程:
    Vue 组件
    import sysInfoWorker from 'worker-loader!./workers/sysInfoWorker'
    
    data () {
      return {
        sysInfoWorker: null
      }
    },
    mounted () {
      this.initSysInfoWorker()
    },
    methods: {
      initSysInfoWorker () {
        this.sysInfoWorker = new sysInfoWorker()
        try {
          this.sysInfoWorker.onmessage = (event) => {
            console.log('sysInfoWorker message:', event)
            this.test = event
          }
          this.sysInfoWorker.onerror = (error) => {
            console.log('sysInfoWorker error:', error)
          }
        } 
        catch (error) {
          console.log(error)
        }
      },
      startSysInfoWorker () {
        this.sysInfoWorker.postMessage({ 
          operation: 'run:getStaticData'
        })
      },
      cancelSysInfoWorker () {
        this.sysInfoWorker.postMessage('cancel:getStaticData')
        // this.sysInfoWorker.terminate()
      }
    }
    
    worker
    const systeminformation = require('systeminformation')
    
    const state = { cancelled: false }
    
    // Listen to messages from parent thread
    self.addEventListener('message', (event) => {
      if (event.data === 'cancel:getStaticData') {
        state.cancelled = true
      }
      else {
        state.cancelled = false
        initWorker(event)
      }
    })
    
    async function initWorker (event) {
      if (event.data.operation === 'run:getStaticData') {
        const info = await systeminformation.getStaticData()
        self.postMessage({ info: info })
      }
    
    }
    
    如果工作人员抛出错误,请尝试将以下内容添加到您的 vue.config :
    module.exports = {
      configureWebpack: {
        module: {
          rules: [
            {
              test: /\.worker\.js$/,
              use: { loader: 'worker-loader' }
            }
    

    关于node.js - Vue Electron 在异步调用一些 Node 库时卡住了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63088031/

    相关文章:

    webpack - VueJS 2 : How To Remove Console. 来自生产版本的日志?

    angular - useAsDefault 不能与 Electron + Webpack 实现一起使用? ( Angular 2)

    google-chrome - 在 electron 和 chrome 之间共享 cookies?

    javascript - 我的快速解析设置有什么问题?

    javascript - 如何安全地评估用户输入表达式

    debian 5 (lenny) 下带有 socket.io 的 node.js 退出并出错

    vuejs2 - 如何在 vuejs 中执行其他操作之前等待函数的响应

    javascript - Vue : Input Form in a component doesn't return a value

    node.js - 如何在Azure中使用Node JS功能上传文件

    reactjs - 使用Electron showOpenDialog Filter允许键入用户*。*,这会使过滤器失败