• JS线程模型&Web Worker


    js线程模型


    客户端javascript是单线程,浏览器无法同时运行两个事件处理程序

    设计为单线程的理论是,客户端的javascript函数必须不能运行太长时间,否则会导致web浏览器无法对用户输入做出响应。这也是为什么Ajax的API都是异步的,以及为什么客户端Javascript不能使用一个简单的异步load()或者require()函数来加载javascript库

    如果应用程序不得不执行太多的计算而导致明显的延迟,应该允许文档在执行这个计算之前完全载入,并且确保告诉用户正在进行计算并且浏览器没有挂起。如果可能应该将任务分散为离散的子任务,可以使用setTimeout()和setInterval()方法在后台运行子任务,同时更新一个进度指示器向用户显示反馈

    Web worker简介


    HTML5定义了一种作为后台线程的WebWorker。 web worker是一个用来执行计算密集任务而不冻结用户界面的后台线程。

    Web worker无法访问window对象和document对象,和主线程之间的通信也只能通过异步消息传递机制来实现。

    Web worker 本身不是轻量级的线程,因而常见一些worker去处理次要的操作是不划算的

    浏览器支持情况:

    包含两部分:

      1. Worker对象:暴露给创建该线程的线程

      2.  WorkerGlobalScope:用来表示新创建的worker的全局对象

    Web Worker基本使用


    创建新的Worker:

    var worker= new Worker("/assets/demo.js");

    传递参数:

    worker.postMessage("file.text");

    接收消息:

    worker.onmessage = function(e){
       var message = e.data;
       ......    
    }

    Worker当然也支持addEventListener()方法和removeEventListener()方法,如果需要管理多个事件时可以使用哒

    异常处理:

    worker.onerror = function(e){
      console.log("Error at " + e.filename + ":" +e.lineno + e.message );
    }

    结束Worker

    worker.terminate();

    载入类和工具函数:

    importScripts("utils/base64.js","utils/Map.js"....);

    注意:importScripts是同步的方法,一旦importScripts方法返回就可以开始使用载入的脚本,不需要回调函数

    Worker作用域


    当创建一个新的Worker时该代码会运行在一个全新的Javascript运行环境中(WorkerGlobalScope),完全与创建Worker的脚本隔离

    WorkerGlobalScope是Worker的全局对象,因而它包含所有核心Javascript全局对象拥有的属性如JSON等,window的一些属性如self等,也拥有类似XMLHttpRequest()函数

    下面简单概括下worker所支持的属性和方法:

    self
    
    setTimeout、clearTimeout、setInterval、clearInterval
    
    location
    
    navigator
    
    onerror
    
    XMLHttpRequest
    
    addEventListener、removeEventListener

    简单例子


    eg1:

    html:

    <div id="div">
            <p>
                计数:
                <output id="result"></output>
            </p>
            <button onclick="startWorker()">开始 Worker</button>
            <button onclick="stopWorker()">停止 Worker</button>
            
            <br />
            <br />
            <button onclick="mainWork()"> click me </button>
            <br />
            <br />
        </div>

    js脚本:

        var w;
    
            function startWorker() {
                if (typeof (Worker) !== "undefined") {
                    if (typeof (w) == "undefined") {
                        w = new Worker("demo.js");
                    }
                    w.onmessage = function(event) {
                        document.getElementById("result").innerHTML = event.data;
                    };
                } else {
                    document.getElementById("result").innerHTML = "Sorry, your browser does not support Web Workers...";
                }
            }
    
            function stopWorker() {
                w.terminate();
            }
            
            function addE(){
                var p = document.createElement('p');
                p.innerHTML="WISH YOU HAPPY~";
                div.appendChild(p);
            }

    demo.js:

    /**
     * Web Worker Demo----count
     * 
     */
     var i=0;
    
    function timedCount()
    {
    i=i+1;
    postMessage(i);
    setTimeout("timedCount()",500);
    }
    
    timedCount();

    结果:

    点击开始Worker后,计数在后台进行,可以点击click me,相互不影响


     eg2:

    如上面所说,我们应该尽量使用WebWorker处理计算量大的,主要的工作,否则因为WebWorker本身不是轻量级的线程,因而有点得不偿失

    本例使用WebWoker处理图片,将图片模糊,顺便学习下canvas,如下:

    html:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <style>
    img {
          width: 400px;
          height: 300px;
        }
    </style>
    </head>
    <body>
    <img src="../images/demo.png" onclick="smear(this)"/>
    <img src="../images/1.png" onclick="smear(this)"/>
    <img src="../images/2.png" onclick="smear(this)"/>
    <script>
        function smear(img){
            var canvas = document.createElement("canvas");
            canvas.width = img.width;
            canvas.height = img.height;
            
            var context = canvas.getContext("2d");
            context.drawImage(img,0,0);
            var pixels = context.getImageData(0,0,img.width,img.height);
            
            var worker = new Worker("SmearWorker.js");
            worker.postMessage(pixels);
            
            worker.onmessage = function(e){
                var smeared_pixels = e.data;
                context.putImageData(smeared_pixels,0,0);
                img.src = canvas.toDataURL();
                worker.terminate();
                canvas.width = canvas.height = 0;
            }
        }
    </script>
    
    </body>
    </html>

     SmearWorker.js:

    /**
     * SmearWorker---smear the picture
     */
     
     function smear(pixels){
         var data = pixels.data,
             width = pixels.width,
             height = pixels.height;
         
         var n = 10,
             m = n-1,
             i,
             col;
             
         for(var row=0; row<height; row++){
             i = row*width*4 + 4;
             for(col =1;col<width; col++,i+=4){
                 data[i] = (data[i] +data[i-4]*m/n);
                 data[i+1] = (data[i+1] +data[i-3]*m/n);
                 data[i+2] = (data[i+2] +data[i-2]*m/n);
                 data[i+3] = (data[i+3] +data[i-1]*m/n);
                 
             } 
         }
         return pixels;
     }
     
     onmessage = function(e){
         postMessage(smear(e.data));
     };

    结果如下:

    图片点击前:

    点击第一张和第三张图片:

     

    其他


    我们在js中使用XMLHttpRequest时经常会设置为异步方式,因而在主浏览器线程张使用同步很不好,我们可以在worker中使用同步的XMLHttpRequest

  • 相关阅读:
    JS经典面试题
    javascript数组(1) ——sort的工作原理及其他数组排序方法
    怎么去掉javascript 的Array的重复项
    Intellij IDEA运行Error ——Command line is too long
    angular-waring:global Angular与local Angular版本不一致问题
    idea(集成python)下载python插件失败
    PLSQL登录oracle显示无监听或协议适配器错误
    maven不能加载ojdbc6.jar的解决方法
    eclipse安装maven插件
    windows下gitbash安装教程
  • 原文地址:https://www.cnblogs.com/wishyouhappy/p/3766225.html
Copyright © 2020-2023  润新知