• 03-web worker vue项目实战


    web worker 网上一大堆讲解,各种互相的复制粘贴,就算讲也是各种不标明版本所对应的配置,断章取义,就算有详细的,也只是在本地的html页面和js中去做的讲解和阐述,那么问题来了,现在基本都用mv**框架吧,就拿vue来说,就没有正儿八经的系统的去描述怎么用的。真是让人头大。。。官方API又说的很简明扼要,需要自己各种尝试。。。

    这里只介绍vue项目中想通过新开一个浏览器线程,用于数据量大,请求的接口比较慢的作为应用场景:

    因为在html和js中去用很简单,在vue cli中因为涉及到了文件打包,所以需要做配置。

    首先,用webpack官方提供的worker-loader这个插件,但是因为又看见了一个叫做vue-worker的插件(是人家封装好的web worker,在vue中可以开箱即用的,不用再在配置文件中去添加一些配置)当然这就很好了,所以我刚开始用的时候作为首选,毕竟怎么简单怎么来嘛~

     第一步:安装

    npm i vue-worker

    第二步:vue中使用

    methods方法中去触发一个方法(比如点击事件),把入参发送给woker线程,worker请求接口

    testFn() {
          this.worker = this.$worker.create([
            {
              message: "reqData",
              // 这个函数是另一个线程的,无法访问外面的任何属性,连window也不行
              func: e => {
                // console.log(window, "wo shi window"); //window is not defined
                console.log("收", e); // 接收到消息之后发送
                var getData = JSON.parse(JSON.stringify(e));
                delete getData.token;
                var url = new URL(process.env.VUE_APP_API_URL + "interviewer");
                var params = getData;
                Object.keys(params).forEach(key =>
                  url.searchParams.append(key, params[key])
                );
                let { token } = e;
                let getInterfaceData = null;
                let resData = null;
                // 要想用async和await 需要配置babel-loader
                async function tempFn() {
                  // 接口一直在pending,不知道怎么回事
                  resData = await fetch(url, {
                    headers: {
                      Accept: "application/json",
                      Authorization: "Bearer " + token
                    }
                  });
                  //
                  let getInterfaceData = await resData.json();
                  console.log(resData, "dsdas");
                }
                tempFn();
                // 原生ajax也是一直pending
                // var xmlhttp = new XMLHttpRequest();
                // xmlhttp.open("GET", url, true);
                // xmlhttp.setRequestHeader("Authorization", "Bearer " + token);
                // xmlhttp.setRequestHeader("Accept", "application/json");
                // xmlhttp.send();
                // xmlhttp.onreadystatechange = function() {
                //   if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                //     console.log(xmlhttp.responseText);
                //   }
                // };
                // console.log("试试", e.context);
                return getInterfaceData;
              }
            }
          ]);
          let sendData = {
            page: this.currentPage,
            per_page: this.pageSize,
            type: 0,
            is_excellent: this.is_excellent,
            is_negative: this.is_negative,
            workcode: this.workcode,
            token: cookie.get("admin_token")
          };
          this.worker.postMessage("reqData", [sendData]).then(function(e) {
            console.log(e, "我是接口发来的数据");
          });
        },
    效果:

     

     两个问题:

    1. func函数里面不能用外面任何属性和引入,所以也就只能用原生fetch 或 ajax开发送接口请求

    2.接口请求一直pending,自然无法拿到数据。那还玩个毛?


    好吧,既然暂时无法有一个好的解决方法,我们暂时换 worker-loader上场为我们服务:

    (此案例是调用了一个列表页面的接口用于测试)

    第一步:安装

    npm i worker-loader (项目依赖)

    第二步:vue.config.js配置

    chainWebpack: config => {
        // 配置
        config.module
          .rule("worker")
          // .test(/.worker.js$/)
          .test(/.worker.(c|m)?js$/i)
          .use("worker")
          .loader("worker-loader")
          .options({
            inline: "fallback",
            filename: "[name].[contenthash].worker.js"
          })
        .end();
    
        // 解决 "window is undefined", 这是因为 worker 线程中不存在 window 对象, 要用 this 代替
        config.output.globalObject("this");
    }

    第三步:在vue组件中引入worker文件

    // 引入存放worker的路径即可(注意,命名必須是xxx.worker.js結尾)
    import myWorker1 from "@/worker/my1.worker.js";

    第四步:在vue組件中的methods中创建实例,然后在created中去调用(初始化)

    getList() {
          // 创建引入的worker实例
          let worker = new myWorker1();
          // 组织worker中接口需要的数据传递给worker
          const params = {
            page: this.currentPage,
            per_page: this.pageSize,
            type: 0,
            is_excellent: this.is_excellent,
            is_negative: this.is_negative,
            workcode: this.workcode,
            // 把登录后拿到的token传过去
            token: cookie.get("admin_token")
          };
          //向工作线程发送消息
          worker.postMessage(params);
          setTimeout(() => {
            worker.onmessage = event => {
              //主线程接收到工作线程的消息
              console.log(event.data.data, "主线程接收");
              // 拿到worker线程请求好的数据,给页面绑定数据
              let getWorkerData = event.data.data;
              if (getWorkerData) {
                this.tableData = getWorkerData.list;
                this.totalCount = getWorkerData.total;
                this.loading = false;
              }
              //关闭线程
              worker.terminate();
            };
          });
    
          worker.onerror = function(error) {
            console.log('错误信息', error, error.message);
            worker.terminate();
          };
    }

    第五步:创建worker文件

    // 请求的接口
    var url = new URL(process.env.VUE_APP_API_URL + "interviewer");
    onmessage = async function(event) {
      // 克隆传来的数据,传来的接口数据中并不需要token,token只是用作鉴权用,拷贝后删掉token属性
      let cloneObj = JSON.parse(JSON.stringify(event.data));
      delete cloneObj.token;
      let params = cloneObj;
      // 把传来的对象格式序列化成查询字符串 ?key=value&xxx=xx,并拼在请求路径的后面,fetch文档并没有对get请求入参的api,需要自己处理
      Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
      //工作线程接收到主线程的消息
      console.log(event.data, "工作线程接收");
      // 发送fetch请求,并携带此项目需要的headers头部信息
      let res = await fetch(url, {
        headers: {
          Accept: "application/json",
          Authorization: "Bearer " + event.data.token
        }
      });
      let data = await res.json();
      if (data) {
        console.log(data, "接口数据");
        // 传给主线程
        postMessage(data);
      }
    };
    //错误信息
    onerror = function(event) {
      console.log(event.message);
    };

    效果:

     

     

     

     

     

     谷歌浏览器worker请求的接口的response是空的:

     

     火狐有:

    至此,列表页中的接口请求就放在worker中去请求了,vue组件中只负责传递接口需要的参数,比如搜索,组织不同的数据过去,worker就会得到不同的入参去重新请求,然后再把请求结果传递给vue组件中(JS线程中),跟平时调接口一样。


     https://webpack.docschina.org/loaders/worker-loader/

    问题有三:

    1. 刷新当前页面,有时候vue组件拿不到worker线程接口请求传来的数据,切换其他路由再切回来就没问题

    2. worker文件中如果有修改,必须重新编译,直接ctrl+s保存不生效,这也是比较纳闷的一个问题,明明在配置的时候filename已经加了hash了。这搞得就跟修改配置文件一般,有点麻烦

    3.worker文件中不能直接import xxx from xxx,比如已经封装好的接口直接拿过来直接xxx.then(),否则编译的时候就卡着不动了,现有解决方法就是用fetch(原生的ajax当然也可以),就是得用原生的请求方法。

     有时间再研究吧。。。。

     

  • 相关阅读:
    Loj #6560 小奇取石子
    某谷 P5153 简单的函数
    某谷 P5159 WD与矩阵
    前端ajax访问 django 报错 POST http://127.0.0.1:8001/xxx 403 (Forbidden)
    python
    Java
    Java
    Java
    Java
    java web 向数据库插入中文数据乱码问题
  • 原文地址:https://www.cnblogs.com/haoqiyouyu/p/14773029.html
Copyright © 2020-2023  润新知