美文网首页
web Worker多线程与离线缓存

web Worker多线程与离线缓存

作者: 心存美好 | 来源:发表于2022-05-18 18:29 被阅读0次

    1. web Worker多线程

    1.1 了解web worder

    JS单线程的问题

    1. 一次只能做一件事。会造成阻塞
    2. 多核 CPU 中,单线程无法发挥计算机的计算能力

    Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。

    worker好处:

    1. 计算密集型或高延迟的任务被worker现成负担了,不会被阻塞或拖慢

    worker的问题:

    1. Worker 线程一旦新建成功,就会始终运行, 会浪费资源,所以不用要及时关闭
    1.2 主线程
    1. 创建worker线程

    主线程通过new命令,调用Worker()构造函数,新建一个 Worker 线程。

    var worker = new Worker('work.js');
    

    Worker()构造函数的参数是一个脚本文件,该文件就是 Worker 线程所要执行的任务。由于 Worker 不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker 就会默默地失败。

    2. 主线程向Worker线程发布数据

    主线程通过调用worker.postMessage()方法,向 Worker线程 发消息。

    worker.postMessage('Hello World');
    

    postMessage()方法的参数:

    就是主线程传给 Worker 的数据。它可以是各种数据类型,包括二进制数据。

    3. 主线程监听Worker线程发送的信息

    主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息。

    worker.onmessage = function (event) {
        // 获取worker线程传递过来的数据
      console.log(event.data);
    }
    

    通过事件对象的data属性可以获取 Worker 发来的数据。

    4. 关闭Worker线程

    在Worker 完成任务以后,主线程就可以把它关闭

    worker.terminate();
    
    1.3 Worker 线程
    1. 监听主线程发布的数据

    Worker 线程通过监听message事件。来获取主线程发布的数据

    self.addEventListener('message', function (e) {
      self.postMessage( e.data);
    }, 
    

    self代表子线程自身,即子线程的全局对象。

    事件对象的data属性包含主线程发来的数据。

    2. 向主线程发布消息

    Worker线程通过self.postMessage()方法用来向主线程发送消息。

    self.postMessage( e.data);
    
    3. 关闭自身线程

    Worker 线程 可以通过 close方法关闭Worker线程

    self.close();
    
    例子:

    两个同步语句,不存在阻塞问题

     <body>
     <div id="box"></div>
      <div id="wrap"></div>
      <script>
        //两个同步语句,不存在阻塞问题
        box.innerHTML='111'
        wrap.innerHTML ='222'
       </script>
    

    存在阻塞问题的语句,前面同步完成后才能渲染222

     <div id="box"></div>
      <div id="wrap"></div>
      <script>
        
        //存在阻塞问题的语句,前面同步完成后才能渲染222
        document.onclick = function () {
          let count = 0;
          for (let i = 0; i < 1000000; i++) {
            count++
          }
          box.innerHTML = count;
          wrap.innerHTML = 222
        }
       </script>
    

    先打印主线程,再打印子线程(理解子线程)

      <div id="box"></div>
      <div id="wrap"></div>
      <script>
        //先打印主线程,再打印子线程(理解子线程)
        document.onclick = function () {
          // let count = 0;
          // for (let i = 0; i < 1000000; i++) {
          //   count++
          // }
          // 创建一个子线程
          console.log('主线程11')
          let work =new Worker('worker.js')//需要创建worker.js文件,写点内容console.log('子线程');console.log(this === self)//this 与 self都表示当前子线程对象。控制台最终结果是子线程最后打印
          console.log('主线程work',work)
          // box.innerHTML = count;
          wrap.innerHTML = 222
        }
        </script>
    

    主线程将复杂的任务放在子线程中执行,并向子线程发送数据

    // index.html(主线程中的代码)
    <body>
      <div id="box"></div>
      <div id="wrap"></div>
      <script>
        document.onclick = function () {
          // 第一步创建一个子线程
          let work = new Worker('worker.js')//需要创建worker.js文件,写点内容console.log('子线程');console.log(this === self)//this 与 self都表示当前子线程对象。控制台最终结果是子线程最后打印
          //第二步 将复杂的任务放在子线程中执行,并向子线程发送数据
          work.postMessage(10000000);
          //  第三步 主线程监听事件接收子线程数据
          work.addEventListener('message', function (ev) {
            console.log('work ev', ev)
            box.innerHTML = ev.data;   //先渲染222,然后再渲染这里的值1000000。这样就不会阻塞 wrap.innerHTML = 222的执行
            this.terminate()//这里执行完了,子线程还是在工作的,所以要通过主线程关闭子线程(外部关闭子线程)。也可在子线程内部关闭self.close()
          }, false)
          wrap.innerHTML = 222
        }
      </script>
    </body>
    
    //worker.js(子线程中的代码)
    //子线程接收数据,监听message事件
    this.addEventListener('message', function (ev) {
        console.log(ev)//控制台中就能看到事件对象,事件对象中的data就是传过来的数据
        let count = 0;
        for (let i = 0; i < ev.data; i++) {
            count++
        }
        //   console.log(count)
        // 子线程通过this 或self把结果传给主线程
        this.postMessage(count)
        // self.close()//关闭线程
    }, false)
    
    1.4 多线程注意点
    1. 同源限制: Worker线程运行的脚本文件必须与主线程的脚本文件同源
    2. DOM限制: Worder线程中不能使用document,window,parent的对象
    3. 文件限制: Worder 线程无法读取本地文件,所加载的必须是网络文件

    2. 离线存储 (offline application)

    HTML5 中可以让我们构建一个离线缓存的应用, 需要创建cache manifest

    什么是离线存储

    离线存储是让web应用在离线的情况下继续使用, 通过manifest文件指明需要缓存的资源

    2.1 离线缓存的优势
    1. 可以配置需要缓存的资源

    2. 离线浏览 - 用户可在应用离线时使用它们

    3. 速度 - 已缓存资源加载得更快, 增强用户体验

    4. 减少请求,缓解服务器负担

    2.2 缓存清单

    缓存清单就是一个普通的文件,其中列出浏览器应该缓存的资源,以供离线时访问. 推荐使用.appcache为后缀名

    2.3 缓存使用

    html标签里使用缓存清单

    <--离线时也能访问到这个页面,在html标签里加上 manifest="xxxxx.appcache"就可以。将来浏览器就会请求这个文件,这个文件里说明哪些文件需要缓存,哪些文件不需要缓存-->
       
    <html lang = "en" manifest="xxxxx.appcache">   
    
    2.4 manifest(appcache) 文件格式
    1. 顶行写 CACHE MANIFEST

    2. CACHE: 指定我们需要缓存的静态资源, 入css, image, js等

    3. NETWORK: (可选) 指定需要在线访问的资源, 可以使用通配符

    4. FALLBACK: (可选) 当被缓存的文件找不到时的备用资源

    2.5 其他
    1. CACHE 可以省略, 这种情况下需要缓存的资源写在CACHE MANIFESR

    2. 可以指定多个CACHE: NETWORK, FALLBACK 无顺序限制

    3. 表示注释

    CACHE MANIFEST
    #这是需要缓存资源CACHE:
    /index.html/222.jpg/333.jpg
    #表示必须在有网络的情况下使用NETWORK:
    /index.css*
    #如果缓存的资源找不到使用备用资源FALLBACK:
    /222.jpg /333.jpg
    
    

    在个互联网中能区分文件类型,因为所有的文件都有一个MIME( 多用途互联网邮件扩展类型 )

    MIME参考手册https://www.w3cschool.cn/media_mimeref.html

    相关文章

      网友评论

          本文标题:web Worker多线程与离线缓存

          本文链接:https://www.haomeiwen.com/subject/paiaurtx.html