首先,這是一篇不嚴謹的博文。javascript
本文僅供參考,沒法在實際生產中運用。html
在捯飭文件分片上傳的過程當中,我老是以爲單線程太慢了。java
因而想,用webWorker唄。node
首先,咱們能夠查看一下WebWorker的兼容性。根據MDN文檔來看,主流瀏覽器都兼容。c++
但有個問題,MDN表示WebWorker只支持到IE10.若是要兼容到ie8,勢必要維護兩份上傳代碼,怎麼破???web
發揮咱們聰明才智的時候到了api
好了,咱們能夠開始開腦洞了,瀏覽器
要聲明的是,咱們只是實現Worker這個假的構造函數。異步
首先,WebWorker在書寫邏輯上是同步的,但其實加載Worker這個行爲是異步的。函數
其次,WebWorker依賴事件與主線程進行溝通,中間通過的數據會被toString()。
再者,WebWorker的api比較簡單,模擬起來也比較方便。
首先來看Worker的interface定義
[Constructor(USVString scriptURL, optional WorkerOptions options), Exposed=(Window,Worker)] interface Worker : EventTarget { void terminate(); void postMessage(any message, optional sequence<object> transfer = []); attribute EventHandler onmessage; attribute EventHandler onmessageerror; }; dictionary WorkerOptions { WorkerType type = "classic"; RequestCredentials credentials = "omit"; // credentials is only used if type is "module" DOMString name = ""; }; enum WorkerType { "classic", "module" }; Worker includes AbstractWorker;
Worker接口繼承了EventTarget,因此還能使用addEventListener removeEventListener這倆api
因此咱們要實現一個假的Worker,須要實現如下內容:
加載Worker腳本
實現如下內容
一步一步來
爲了模擬Worker的同步書寫方式
咱們須要實現一個同步加載腳本的方法 (●゚ω゚●)
注:在現代瀏覽器裏已經不同意使用了
(function (root) { var cache = {}; // debug window.__rc = cache; var module = {}; module.exports = null; var config = { rootPath: '' }; function hash(str) { var hash = 5381, i = str.length; while(i) { hash = (hash * 33) ^ str.charCodeAt(--i); } /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed * integers. Since we want the results to be always positive, convert the * signed int to an unsigned by doing an unsigned bitshift. */ return hash >>> 0; } var defaultShimFunction = function (code, f) { if (f) { return f.replace('[[code]]', code); } return code; }; root.require = function (scriptPath, shim) { var path = scriptPath; shim = shim || ''; if (/^(\/|https?:\/\/)/.test(scriptPath) !== true) { path = config.rootPath + scriptPath; } if (/\.js$/.test(path) === false) { path += '/index.js'; } var keyName = path + '?hash=' + hash(shim); if (cache[path]) { if (cache[keyName]) { return cache[keyName] } eval(defaultShimFunction(cache[path], shim)); return cache[keyName] = module.exports; } var request = new XMLHttpRequest(); request.open('GET', path, false); request.send(null); if (request.status === 200) { cache[path] = request.responseText; eval(defaultShimFunction(cache[path], shim)); cache[keyName] = module.exports; } return cache[keyName]; }; root.require.config = function (opts) { for (var i in opts) { config[i] = opts[i] } }; }(window));
(๑´ㅂ`๑)上述代碼不要在乎,主要實現的功能其實就是特別智障的在瀏覽器裏同步加載commonjs模塊。。。
加了個墊片,方便操做
萬事具有,只欠東風
來吧,直接上代碼,worker-ployfill.js
window.__wbus = { _lis: {}, on: function (evt, fn) { this._lis[evt] = fn; }, off: function (evt) { if (!evt) { this._lis = {}; return; } delete this._lis[evt]; delete this._lis['close' + evt]; }, emit: function (evt, data) { this._lis[evt] && this._lis[evt](data); } }; function copy (a) { if (typeof a === 'object') { var c = JSON.stringify(a); return JSON.parse(c); } return a; } function FakeEvent (data, id) { this.data = copy(data); this.type = 'message'; this.id = id; } var uuid = 1; var FakeWorker = function (p) { var self = this; self._id = uuid++; window.__wbus.on(self._id, function (data) { var Fe = new FakeEvent(data, self._id); self.onmessage && self.onmessage.call(Fe, Fe); }); window.__wbus.on('close' + self._id, function (data) { self.terminates(); }); var path = location.protocol + '//' + location.host + '/' + p; var wf = require(path, ' module.exports = function () {\ var self = {};\ self.postMessage = function (data) {\ window.__wbus.emit(' + self._id + ', data);\ };\ self.onmessage = function () {};\ self.close = function () { window.__wbus.emit(close' + self._id + ') };\ [[code]]\ ;return self;\ }\ '); this.worker = wf(); }; FakeWorker.prototype.onmessage = function () { }; FakeWorker.prototype.postMessage = function (data) { if (!this.worker) { throw new ReferenceError('Worker already stoped!'); } var d = new FakeEvent(data, this._id); this.worker.onmessage && this.worker.onmessage.call(d, d); }; FakeWorker.prototype.terminates = function () { this.worker = null; window.__wbus.off(this._id); }; module.exports = FakeWorker;
智障兒童歡樂多。
來,讓咱們玩一把吧,下面是測試代碼。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>測試23333</title> </head> <body> <span> {{text}} </span> <script type="text/javascript" src="/static/js/require.js"></script> <script type="text/javascript"> require.config({ rootPath: '/node_modules/' }); </script> <script type="text/javascript"> var Worker = require('/static/js/worker-ployfill.js'); var cpus = require('cpus/browser.js')().length; var workers = []; for (var i = 0; i < cpus; i ++) { workers[i] = new Worker('static/js/worker-test.js'); } workers.forEach((item) => { item.onmessage = function (e) { console.log('main thread'), console.log('thread id: %s', e.id); console.log('msg: %s', JSON.stringify(e.data)); }; item.postMessage({ message: 'message from main' }); }) </script> </body> </html>
// worker-test.js self.onmessage = function (e) { console.log('worker thread'), console.log('thread id: %s', e.id); console.log('msg: %s', JSON.stringify(e.data)); self.postMessage({ message: 'from FackWorker' }); };
你看,智障系列
233333333.