搞笑向, 面向IE8的webworker-ployfill

首先,這是一篇不嚴謹的博文。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腳本

    • 加載規則爲同域名,從根目錄開始尋找。
    • 暫不作blob生成,對本篇文章主題而言沒有意義。
  • 實現如下內容

    • 實現onmessage
    • 實現onmessageerror (文章中暫不實現)
    • 實現close
    • 實現terminate (文章中暫不實現)
    • 實現addEventListener (文章中暫不實現)
    • 實現removeEventListener (文章中暫不實現)
    • 實現個假事件。

一步一步來


爲了模擬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.

相關文章
相關標籤/搜索