├── LICENSE.txt ├── README.md ├── package.json ├── subworkers.js └── test ├── blob-browser.js ├── browser.js ├── child-worker.js ├── main-worker-blob.js ├── main-worker.js └── test.html /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 David Mihal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Subworkers 2 | WebWorkers are awesome! Unfortionately, Google Chrome doesn't support creating subworkers, 3 | [here's the Chromium issue for it](https://code.google.com/p/chromium/issues/detail?id=31666). 4 | 5 | This polyfill provides this functionality to Chrome and any other browser that supports WebWorkers, 6 | but not subworkers. This functionality is implemented by creating all subworkers in the context of 7 | the main page and simulating the communication. 8 | 9 | ## Usage 10 | Using this is easy! 11 | 12 | 1. Download [`subworkers.js`](https://raw.githubusercontent.com/dmihal/Subworkers/master/subworkers.js) 13 | 2. In the document hosting the WebWorkers, include the `subworkers.js` script before any scripts that create WebWorkers. 14 | 15 | ``` html 16 | 17 | ``` 18 | 19 | 3. In the code for any WebWorker that will have a subworker, you also need to include `subworkers.js`. 20 | 21 | ``` javascript 22 | importScripts("subworkers.js"); 23 | ``` 24 | 25 | That's it! WebWorkers now work the way you would expect! 26 | 27 | ### With NPM 28 | 29 | 1. Install subworkers.js by running `npm install -s subworkers` 30 | 2. Import the library in all scripts 31 | 32 | ``` javascript 33 | require('subworkers'); // CommonJS 34 | // or 35 | import 'subworkers'; // ES2015+ 36 | ``` 37 | 38 | ## License 39 | This project is released under the MIT License. 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "subworkers", 3 | "version": "1.0.0", 4 | "description": "Polyfill to allow nested WebWorkers Edit", 5 | "main": "subworkers.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/dmihal/Subworkers.git" 12 | }, 13 | "author": "David Mihal", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/dmihal/Subworkers/issues" 17 | }, 18 | "homepage": "https://github.com/dmihal/Subworkers#readme" 19 | } 20 | -------------------------------------------------------------------------------- /subworkers.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | /* Detect if we're in a worker or not */ 4 | var isWorker = false; 5 | try { 6 | document; 7 | } catch (e){ 8 | isWorker = true; 9 | } 10 | 11 | if (isWorker){ 12 | if (!self.Worker){ 13 | self.Worker = function(path){ 14 | var that = this; 15 | this.id = Math.random().toString(36).substr(2, 5); 16 | 17 | this.eventListeners = { 18 | "message": [] 19 | }; 20 | self.addEventListener("message", function(e){ 21 | if (e.data._from === that.id){ 22 | var newEvent = new MessageEvent("message"); 23 | newEvent.initMessageEvent("message", false, false, e.data.message, that, "", null, []); 24 | that.dispatchEvent(newEvent); 25 | if (that.onmessage){ 26 | that.onmessage(newEvent); 27 | } 28 | } 29 | }); 30 | 31 | var location = self.location.pathname; 32 | var slashedPath = path.charAt(0) == '/' ? path : '/' + path; 33 | var absPath = location.substring(0, location.lastIndexOf('/')) + slashedPath; 34 | self.postMessage({ 35 | _subworker: true, 36 | cmd: 'newWorker', 37 | id: this.id, 38 | path: absPath 39 | }); 40 | }; 41 | Worker.prototype = { 42 | onerror: null, 43 | onmessage: null, 44 | postMessage: function(message, transfer){ 45 | self.postMessage({ 46 | _subworker: true, 47 | id: this.id, 48 | cmd: 'passMessage', 49 | message: message, 50 | transfer: transfer, 51 | }, transfer); 52 | }, 53 | terminate: function(){ 54 | self.postMessage({ 55 | _subworker: true, 56 | cmd: 'terminate', 57 | id: this.id 58 | }); 59 | }, 60 | addEventListener: function(type, listener, useCapture){ 61 | if (this.eventListeners[type]){ 62 | this.eventListeners[type].push(listener); 63 | } 64 | }, 65 | removeEventListener: function(type, listener, useCapture){ 66 | if (!(type in this.eventListeners)) { 67 | return; 68 | } 69 | var index = this.eventListeners[type].indexOf(listener); 70 | if (index !== -1){ 71 | this.eventListeners[type].splice(index, 1); 72 | } 73 | }, 74 | dispatchEvent: function(event){ 75 | var listeners = this.eventListeners[event.type]; 76 | for (var i = 0; i < listeners.length; i++) { 77 | listeners[i](event); 78 | } 79 | } 80 | }; 81 | } 82 | } 83 | 84 | var allWorkers = {}; 85 | var cmds = { 86 | newWorker: function(event){ 87 | var worker = new Worker(event.data.path); 88 | worker.addEventListener("message", function(e){ 89 | var envelope = { 90 | _from: event.data.id, 91 | message: e.data 92 | } 93 | event.target.postMessage(envelope); 94 | }); 95 | allWorkers[event.data.id] = worker; 96 | }, 97 | terminate: function(event){ 98 | allWorkers[event.data.id].terminate(); 99 | }, 100 | passMessage: function(event){ 101 | allWorkers[event.data.id].postMessage(event.data.message, event.data.transfer); 102 | } 103 | } 104 | var messageRecieved = function(event){ 105 | if (event.data._subworker){ 106 | cmds[event.data.cmd](event); 107 | } 108 | }; 109 | 110 | 111 | /* Hijack Worker */ 112 | var oldWorker = Worker; 113 | Worker = function(path){ 114 | if (this.constructor !== Worker){ 115 | throw new TypeError("Failed to construct 'Worker': Please use the 'new' operator, this DOM object constructor cannot be called as a function."); 116 | } 117 | 118 | var blobIndex = path.indexOf('blob:'); 119 | 120 | if (blobIndex !== -1 && blobIndex !== 0 ) { 121 | path = path.substring(blobIndex); 122 | } 123 | 124 | var newWorker = new oldWorker(path); 125 | newWorker.addEventListener("message", messageRecieved); 126 | 127 | return newWorker; 128 | }; 129 | 130 | })(); 131 | -------------------------------------------------------------------------------- /test/blob-browser.js: -------------------------------------------------------------------------------- 1 | var mainWorker = new Worker("main-worker-blob.js"); 2 | mainWorker.postMessage("start"); 3 | mainWorker.addEventListener("message",function (e) { 4 | if (e.data === "success"){ 5 | document.getElementById("blob-url-output").textContent = "Success!"; 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /test/browser.js: -------------------------------------------------------------------------------- 1 | var mainWorker = new Worker("main-worker.js"); 2 | mainWorker.postMessage("start"); 3 | mainWorker.addEventListener("message",function (e) { 4 | if (e.data === "success"){ 5 | document.getElementById("url-output").textContent = "Success!"; 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /test/child-worker.js: -------------------------------------------------------------------------------- 1 | self.addEventListener('message',function(e){ 2 | if (e.data === "ping"){ 3 | self.postMessage("pong"); 4 | } 5 | }); 6 | -------------------------------------------------------------------------------- /test/main-worker-blob.js: -------------------------------------------------------------------------------- 1 | importScripts("../subworkers.js"); 2 | 3 | var childWorkerStr = ''; 4 | childWorkerStr += "self.addEventListener('message',function(e){"; 5 | childWorkerStr += " if (e.data === 'ping'){"; 6 | childWorkerStr += " self.postMessage('pong');"; 7 | childWorkerStr += " }"; 8 | childWorkerStr += "});"; 9 | 10 | var childfWorkerURL = URL.createObjectURL( 11 | new Blob([ childWorkerStr ], {type: 'text/javascript'}) 12 | ); 13 | 14 | var subWorker = new Worker(childfWorkerURL); 15 | subWorker.addEventListener('message',function(e){ 16 | if (e.data === "pong"){ 17 | self.postMessage("success"); 18 | } 19 | }); 20 | 21 | self.addEventListener('message',function(e){ 22 | if (e.data === "start"){ 23 | subWorker.postMessage("ping"); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /test/main-worker.js: -------------------------------------------------------------------------------- 1 | importScripts("../subworkers.js"); 2 | var subWorker = new Worker("child-worker.js"); 3 | subWorker.addEventListener('message',function(e){ 4 | if (e.data === "pong"){ 5 | self.postMessage("success"); 6 | } 7 | }); 8 | 9 | self.addEventListener('message',function(e){ 10 | if (e.data === "start"){ 11 | subWorker.postMessage("ping"); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Subworker Test

10 |

Subworker

11 |
12 |     
13 |

Subworker with Blob URL

14 |
15 |     
16 | 17 | 18 | --------------------------------------------------------------------------------