zoukankan      html  css  js  c++  java
  • Web Worker

    1.什么是Web Worker?

    在web worker规范产生之前,dom渲染和javascript代码执行是在同一个浏览器线程中执行的。也就是说:渲染dom的时候不能执行javascript代码,执行javascript代码的时候,UI界面会暂停响应。如果javascript代码执行时间很长,那么UI就会无响应,这就是所谓的页面卡死。Web Workers是 HTML5 提供的一个javascript多线程解决方案,我们可以将一些耗时的javascript代码交由web Worker运行而不冻结用户界面。也就是说web worker和UI界面是运行在不同线程中的。
     

    2.检测浏览器对Web Worker支持

    web worker是HTML5中新增的特性,一般的主流浏览器都是支持的,但不是所有的浏览器都支持。我用的是chrome 46,是支持web worker的。我们可以使用下面这段代码,来检测浏览器是否支持web worker。
    [javascript] view plain copy
     
    1. if(typeof(window.Worker)!=="undefined")  
    2. {  
    3.     // Yes! Web worker support!  
    4. }  
    5. else  
    6. {  
    7.     // Sorry! No Web Worker support..  
    8. }  

    3.创建web worker文件

    web worker一般是存放在一个单独的js文件中,由使用它的html页面来加载。
    [javascript] view plain copy
     
    1. //my_worker.js  
    2.   
    3. //这里this并不是传统意义上的window对象,而是一个WorkGlobalScope对象  
    4. var self = this;  
    5.   
    6.   
    7. // worker入口,类似于Thread的run方法  
    8. self.onmessage = function(evt){  
    9.       
    10.     // 接收传递过来的参数  
    11.     var millSeconds = evt.data;  
    12.       
    13.     wait(millSeconds);  
    14.       
    15.     console.log("work time is: " + new Date());  
    16.       
    17.     // 返回数据给调用者  
    18.     postMessage("from worker's message.");  
    19. }  
    20.   
    21.   
    22. function wait(millSeconds)  
    23. {  
    24.     var begin = new Date().getTime();  
    25.     var end = new Date().getTime();  
    26.     while(end - begin < millSeconds)  
    27.     {  
    28.         end = new Date().getTime();  
    29.     }  
    30. }  

    worker新线程使用通过postMessage和onmessage方法:
    1.通过postMessage( data ) 方法来向主线程发送数据。
    2.绑定onmessage方法来接收主线程发送过来的数据。
     
     

    4.创建Web Worker对象

    有了web worker文件之后,我们就可以在自己的HTML页面中调用它。
    [html] view plain copy
     
    1. <!DOCTYPE HTML>  
    2. <html>  
    3. <head>  
    4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>  
    5.     <script type="text/javascript">  
    6.         // 开启一个web worker线程(加载js文件,创建worker对象)  
    7.         var worker =new Worker("my_worker.js");   
    8.           
    9.         // 传递数据给work  
    10.         worker.postMessage(5000);       
    11.           
    12.         console.log("continue ...");  
    13.           
    14.         // 接收work返回的数据  
    15.         worker.onmessage =function(evt){      
    16.             console.log("main now is: " + new Date());              
    17.             console.log(evt.data);                
    18.         }  
    19.           
    20.         console.log("no wait ...");  
    21.           
    22.     </script>  
    23.  </head>  
    24. <body></body>  
    25. </html>  

    我们的main.htm(WEB主线程)主要做以下事情:
    1.通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。
    2.通过worker.postMessage( data ) 方法来向worker发送数据。
    3.绑定worker.onmessage方法来接收worker发送过来的数据。
    4.使用 worker.terminate() 来终止一个worker,释放占用的资源。
     

    5.运行含Web Worker的页面

    上面的main.html页面使用了Web Work,必需将main.html和my_worker.js部署到web容器(比如Tomcat)下才能运行。如果直接在本地运行main.html页面,会报错:
    [plain] view plain copy
     
    1. Uncaught SecurityError: Failed to construct 'Worker': Script at 'file:///C:/Users/a00228097/Desktop/work/worker.js' cannot be accessed from origin 'null'.  
    这是因为我用的是chrome浏览器,chrome不支持这种本地使用本地方式使用Web Worker。不过别的浏览器可能就支持,所以还是把main.html页面放在web容器中运行更靠谱。

    6.Web Worker的跨域访问限制

    在main.html中通过new Work(url)来创建work对象,加载的js文件不能跨域。比如我们将main.html放在端口是8080的Tomcat下,将my_worker.js放在端口是9090的Tomcat下,那么main.html是不能使用my_work.js的。
    [javascript] view plain copy
     
    1. var worker =new Worker("http://localhost:9090/demo/my_worker.js");   
    2. /* 
    3. Uncaught SecurityError: Failed to construct 'Worker':  
    4.     Script at 'http://localhost:9090/demo/my_worker.js'  
    5.     cannot be accessed from origin 'http://localhost:8080'. 
    6. */  

    7.Web Worker的异常处理和终止

    WEB主线程加载web worker一般没有什么异常,不过也有2种情况会导致创建web work报错,比如我们跨域访问web worker文件,再比如web work中的js代码出现了未捕获的异常。如果main.html需要关注这些异常,那么我们可以使用onerror回调:
    [javascript] view plain copy
     
    1. var worker =new Worker("my_worker.js");   
    2.     
    3. worker.onerror = function(e){  
    4.     console.log("load web worker error."+e);  
    5. };  

    当main.html不再需要使用web worker的时候,需要调用worker对象的terminate()方法来释放web worker占用的资源。
    [javascript] view plain copy
     
    1. worker.terminate();  

    8.web worker中使用importScripts加载外部js

    我们知道在html页面中,可以使用<script>标签加载外部的js文件,而且script标签还支持跨域加载js。如果我们的web worker中也需要访问外部的js文件,那么可以使用importScripts函数来加载文件,而且也是跨域的。
    [javascript] view plain copy
     
    1. //my_worker.js  
    2.   
    3.   
    4. var self  =this;  
    5. importScripts("http://localhost:9090/demo/util.js");  
    6. importScripts("math.js");  
    7.   
    8. onmessage = function(evt){  
    9.       
    10.     var millSeconds = evt.data;  
    11.       
    12.     wait(millSeconds);  
    13.       
    14.     console.log("work time is: " + new Date());  
    15.     postMessage("from worker's message.");  
    16.       
    17.     warn("sss");//调用util.js中的warn函数  
    18. }  
    19.   
    20.   
    21. function wait(millSeconds)  
    22. {  
    23.     var begin = new Date().getTime();  
    24.     var end = new Date().getTime();  
    25.     while(end - begin < millSeconds)  
    26.     {  
    27.         end = new Date().getTime();  
    28.     }  
    29. }  

    importScripts使用方式如下:
    [javascript] view plain copy
     
    1. importScripts('script1.js');  
    2. importScripts('script2.js');  
    3.   
    4. //Which can also be written as a single import statement:  
    5. importScripts('script3.js', 'script4.js');  

    9.Web Work的局限性

    在web worker的js中无法访问main.html中的DOM对象、window对象、document对象等,这是属于功能上的局限性。还有不同厂家的浏览器对Web Worker规范的实现并不一致,导致运行效果的差异。这篇文章介绍了web worker中一些API的不兼容性。所以使用web worker需要小心,不然会导致功能性问题和兼容性问题。
     

    10.使用Blob URL实现Web Worker的inline

    一般来说web worker都是放在一个单独的外部js文件中的,这就是最佳实践。如果只是为了自己平时测试需要,将web worker和main.html放在一起也是可以的。需要借助window.URL.createObjectURL()来实现inline。比如下面的main.html是可以正常运行的。
    [html] view plain copy
     
    1. <!DOCTYPE HTML>  
    2. <html>  
    3. <head>  
    4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>  
    5.     <script type="text/javascript">  
    6.     var blob = new Blob(["onmessage = function(e) { postMessage('msg from worker'); }"]);  
    7.   
    8.     // Obtain a blob URL reference to our worker 'file'.  
    9.     var blobURL = window.URL.createObjectURL(blob);  
    10.   
    11.     var worker = new Worker(blobURL);  
    12.     worker.onmessage = function(e) {  
    13.         console.log(e.data);  
    14.     };  
    15.       
    16.     worker.postMessage(1); // Start the worker.  
    17.           
    18.     </script>  
    19.  </head>  
    20. <body></body>  
    21. </html>  
     
     
    参考文章:
     
     
  • 相关阅读:
    Ubuntu18.04可执行文件运行提示No such file or directory
    Linux gcc(ar命令)打包库到另一个库中的另外一种方法
    干干净净的grep
    C语言里面和时间有关的函数
    Ubuntu上安装tftp服务
    因为新冠,宅家2周,折腾了一下电视盒子。
    批量处理文件的Python程序
    Windows 10中使用VirtualBox
    重采样Resample 的一些研究记录。
    微信公众号接入第三方服务器,设置自动回复、关键回复、自定义菜单,配置及开发流程
  • 原文地址:https://www.cnblogs.com/zhxling/p/5241439.html
Copyright © 2011-2022 走看看