在web worker中使用fetch实例详解

2022-11-17 09:05:44
目录
1.Web Worker意义2. 主线程的使用创建通信错误处理关闭3. 子线程的使用和主线程的通信加载其他脚本关闭4. 在WebWorker中使用fetch5. 实现思路

1.Web>

由于 JS 是单线程的,费时的 JS 操作将会导致整个页面的阻塞。Web Worker 提供了创建多线程的方法,将一些耗时且 UI 无关的工作交给 worker,可提高页面的使用体验。

限制:

同源策略:worker 线程执行的脚本要和当前页面同源

API 限制:

    不能操作 DOM不能使用 window 的全局变量,但可以使用 navigator 和 location 对象不能使用 alert、confirm 方法无法读取本地文件

    和主线程不在一个上下文环境,通讯要通过 postMessage 完成

    2.>

    创建

    创建一个子线程,要传入一个脚本的>

    const worker = new Worker('url');
    

    如果要在本文件中描述执行的内容,可以用 Blob 和 window.URL.createObjectURL 生成一个 URL

    function createWorker(f) {
      const blob = new Blob(['(' + f.toString() +')()']);
      const url = window.URL.createObjectURL(blob);
      const worker = new Worker(url);
      return worker;
    }
    

    通信

      主线程>
      worker.postMessage(param);
      

      参数可以是任意类型,包括二进制数据。但传递是拷贝形式而不是引用形式。因此对于大数据会存在性能问题。

        子线程 => 主线程
        worker.onmessage = function (event) {
          console.log('Received message ' + event.data);
        }
        

        错误处理

        worker.onerror(function (e) {
          console.log([
            'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
          ].join(''));
        });
        

        关闭

        worker.terminate();
        

        3.>

        子线程中无法使用 window,self 代表全局对象

        和主线程的通信

          主线程>
          self.addEventListener('message', function (e) {
            self.postMessage('Received: ' + e.data);
          }, false);
          
            子线程 => 主线程
            self.postMessage('something');
            

            加载其他脚本

            在子线程中加载其他脚本:

            importScripts('script1.js', 'script2.js');
            

            关闭

            self.close();
            

            4.>

            网络请求是和DOM无关且可能耗时较长的操作,worker线程支持使用Fetch,是适合放在worker中进行的操作。

            而要在worker中使用fetch,如果每次都要自己处理线程间的通信的话,会十分麻烦,因此我对通信进行了封装,写成了一个可以直接使用的库。

            安装依赖:

            npm i web-worker-fetch
            

            使用时先实例化一个WF对象,然后就可以像使用fetch一样在worker中使用fetch:

            import WebWorkerFetch from "web-worker-fetch";
            const wf = new WebWorkerFetch();
            wf.fetch("url", {
              method: "POST", // *GET, POST, PUT, DELETE, etc.
              mode: "cors", // no-cors, *cors, same-origin
              cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
              credentials: "same-origin", // include, *same-origin, omit
              headers: {
                "Content-Type": "application/json"
                // 'Content-Type': 'application/x-www-form-urlencoded',
              },
              redirect: "follow", // manual, *follow, error
              referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
              body: JSON.stringify(data) // body data type must match "Content-Type" header
            }).then((res) => console.log(res));
            

            除此之外,借鉴 axios 的思路,配置中可以提供 requestInterceptorresponseInterceptor,对请求参数和返回数据做统一处理

            5.>

            这个库的封装主要是解决了两个问题:

              发送请求时如何把参数传递给worker线程请求结束后如何从worker线程获取结果

              对于第一个问题,主线程使用 ostMessage 向worker线程传递参数。

              对于第二个问题,worker线程通过 self.postMessage 向主线程传递消息,主线程通过 worker.onmessage 监听消息。

              此时就引出了问题所在:如果多次使用 wf.fetch 发送请求,那么在一个请求完成后,worker线程触发的消息将让所有请求处都认为请求已完成。

              因此,在每次请求时,使用一个fetchId确定该请求做唯一性。将该id传给worker线程,后续worker线程向主线程通信时也会带上这个id。

              在主线程中监听onmessage事件时,判断id是否和自己的请求id一致,只有在相同时才做处理。

              具体的实现大家可以移步仓库源码,实际上也非常简单。

              以上就是在web worker中使用fetch实例详解的详细内容,更多关于web worker使用fetch的资料请关注易采站长站其它相关文章!