美文网首页前端知识HTML
webworker使用介绍,js中开启多线程

webworker使用介绍,js中开启多线程

作者: 虚幻的锈色 | 来源:发表于2017-03-02 20:56 被阅读2097次

    【Webworker】

    注:必须要在服务器环境。

    什么是webworker?
    Web Worker为Web应用程序提供了一种能在后台中运行的方法。通过Web Worker可以生成多个线程同时运行,并保证页面对用户的及时响应,完全不会影响用户的正常操作。

    单线程:单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。简单的说就是处理事务的任务链,当只有一条链,所有的事情都在这一条链上执行时,那就是单线程。

    优点:单线程较多线程来说,系统稳定、扩展性极强、软件丰富。

    缺点:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)。

    多线程:有多条链时,那就是多线程了,当然并不是说多条线并行,而是说有一条主线程,处理整个程序任务的主方向的链,而其链上又有许许多多的分支,就像树枝那样,这样,既有了主线程去处理那些主要任务,又有了那些细小线程去处理耗时费力任务,从而让界面看起来更加流畅。

    不容置疑的事实是:Javascript是单线程的,基于其特殊的用途,为了避免复杂性,从一开始,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。所以一定要明确这一点,同时也要理解对这个单线程的概念,理解不好就容易糊涂。JS的单线程是指一个浏览器进程中只有一个JS的执行线程,同一时刻内只会有一段代码在执行,但是浏览器有很多线程,是多线程的,当js线程在执行时,浏览器可以根据需求开相应的线程进行处理。

    那能不能开启js的多线程?
    可以,html5的webworker允许javascript多线程。

    多线程是在原有主线程之外分了worker线程出来,但是子线程完全受主线程控制,且不得操作DOM。因为Worker线程不能直接访问和操作页面中的DOM属性,如果Worker线程需要访问页面中的某个DOM节点,必须通过postMessage API发消息给主线程,主线程在收到消息后获取页面中的某个DOM节点的属性,再通过postMessage的方式回传给Worker线程,这样就避免了冲突。

    那么怎么使用webworker多线程呢?

    首先说一下webworker使用的代码说明:

    WEB主线程:

    1.通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。

    2.通过worker.postMessage( data ) 方法来向worker发送数据。

    3.绑定worker.onmessage方法来接收worker发送过来的数据。

    4.可以使用 worker.terminate() 来终止一个worker的执行。

    worker子线程:

    1.通过postMessage( data ) 方法来向主线程发送数据。

    2.绑定onmessage方法来接收主线程发送过来的数据。

    开始编写程序

    1)创建一个Worker:

    通常,与web worker相关的代码都放在一个独立的JavaScript文件中。父线程通过在Worker构造函数中指定一个JavaScript文件的链接来创建一个新的worker,它会异步加载并执行这个JavaScript文件。

    //var oW = new Worker(子线程路径);
    //var oW = new Worker('a.js');
    //console.log(oW); //对象 身上有很多数据
    
    var oW = new Worker('a.js'); //创建
    oW.postMessage('12');  //方法来向worker发送数据。
    

    2)编写子线程a.js:

    this.onmessage = function(ev){
        console.log(ev.data);  // html页面输出12   注:子线程没有alert
    };
    
    //*********************************
    
    this.onmessage = function(ev){
        console.log(typeof ev.data);  //html页面输出string  注意:传过来数据形式是什么接受就是什么。
    };
    
    

    注意:

    1.子线程进行计算,不能进行 DOM BOM操作
    2.子线程不能跨域,文件需放在同路径中
    3.子线程不能套子线程
    4.子线程 不和主线程共享数据,而是复制一份儿 哪怕是对象

    子线程可以直接输入运算:

    //主线程html页面
    var oW = new Worker('b.js');
    oW.postMessage(alert);
    
    //子线程b.js
    this.onmessage = function(ev){
    console.log(ev.data+5);    //  10  
    };
    

    可以利用子线程为我们做一些计算:

    var oW = new Worker('c.js');
    oW.postMessage(12);  //向子线程发送数据
    oW.onmessage = function(ev){ //接收字线程发送过来的数据
    alert(ev.data);  //17
    };
    
    //子线程c.js
    this.onmessage = function(ev){  //接收主线程发送过来的数据
    this.postMessage(ev.data+5);  //向主线程发送数据
    };
    

    子线程不和主线程共享数据,而是复制一份儿,哪怕是对象:

    变量:

    //主线程html页面
    var oW = new Worker('d.js');
    var a = 12;
    oW.postMessage(a);
    oW.onmessage = function(ev){
        alert(ev.data);//17
    };
    alert('主线程:'+a); //12
    
    //子线程d.js
    this.onmessage = function(ev){
        this.postMessage(ev.data+5);
    };
    

    对象:

    //主线程html页面
    var oW = new Worker('e.js');
    var arr = [12,5,8];
    oW.postMessage(arr);
    oW.onmessage = function(ev){
        alert('子线程'+ev.data);//[101,5,8]
    };
    alert('主线程'+arr);//12,5,8
    
    //子线程e.js
    this.onmessage = function(ev){
        ev.data[0] = 101;
        console.log(ev.data);
        this.postMessage(ev.data);
    };
    

    那么怎么测试到底有没有是多线程?如果确定子线程是否运行呢?

    那么我就说一下我的思路:
    1、先写一个可以让程序进入暂时性假死状态的函数,

    function fn(n){ //写一个可以让程序假死的函数
        if(n<=2){
            return 1;  // 如果我们传进来的小于等于2 就走这个。
        }else{
            return fn(n-2)+fn(n-1);  //如果我们传进来的大于2,就一直自动的持续调用自己,直到小于2。这样可以让系统进入假死状态,需要处理很长时间才结束。
        }
    }
    

    2、然后写出四个按钮,
    第一个点击后,直接传入一个大一2的数,调用函数,让程序假死。
    第二个点击后,会调用一个子线程,子线程里面有同样的函数,也来执行调用。
    第三个点击后:出测试结果后,直接中断子线程,等的时间确实长。。你懂得。。
    第四个点击后:页面正常弹1
    3、开始写子线程

    //和主线程同样的函数
    function fn(n){
        if(n<=2){
            return 1;
        }else{
            return fn(n-2)+fn(n-1);
        }
    }
    this.onmessage = function(ev){
        this.postMessage(fn(ev.data));  //给主线程返回调用函数处理后的数据
    };
    

    4、开始编写页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>前端开发工程师-李鹏</title>
        <style>
    
        </style>
        <script>
    function fn(n){ //写一个可以让程序假死的函数
        if(n<=2){
            return 1;  // 如果我们传进来的小于等于2 就走这个。
        }else{
            return fn(n-2)+fn(n-1);  //如果我们传进来的大于2,就一直自动的持续调用自己,直到小于2。这样可以让系统进入假死状态,需要处理很长时间才结束。
        }
    }
            document.addEventListener('DOMContentLoaded',function(){
                var aBtn = document.querySelectorAll('input');
                var oW;//因为要做四个点击按钮,所以让线程为全局变量
                aBtn[0].onclick = function(){ //点击的时候 直接调用函数 让程序假死,然后点击第四个按钮,测试看看能不能弹1
                    alert(fn(48));
                };
                aBtn[1].onclick = function(){ //点击的时候让子线程来执行这个 同样的函数,然后点击第四个按钮,测试看看能不能弹1
                    oW = new Worker('fib.js');
                    oW.postMessage(48);
                    oW.onmessage = function(ev){alert(ev.data);};
                };
                aBtn[2].onclick = function(){ //测试成功后就用来终止子线程,,因为等待时间确实长。。你懂得
                    oW.terminate();
                };
                aBtn[3].onclick = function(){  //作为测试函数。
                    alert(1);
                };
    
            },false);
    
    
        </script>
    </head>
    <body>
    <input type="button" value="开启主线程">
    <input type="button" value="开启子线程">
    <input type="button" value="关闭进程">
    <input type="button" value="测试">
    </body>
    </html>
    

    结果:
    点击第一个后,直接执行假死函数,让程序假死,在点击第四个按钮,没有作用,不会立即弹1,只有等待很长时间之后假死函数执行完毕后, 才会弹1。
    点击第二个后,让子线程来执行假死函数,让程序假死,在点击第四个按钮,直接就会立即弹1,随时点,随时弹,等待很长时间后假死函数执行完毕后,弹结果。
    可以复制自己去测试。
    以上结束。

    相关文章

      网友评论

        本文标题:webworker使用介绍,js中开启多线程

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