Веб-работники без отдельного файла Javascript? - PullRequest
270 голосов
/ 23 марта 2011

Насколько я могу судить, веб-работники должны быть написаны в отдельном файле JavaScript и называться так:

new Worker('longrunning.js')

Я использую компилятор закрытия для объединения и минимизации всего моего исходного кода JavaScript, и я бы не хотел, чтобы мои работники размещались в отдельных файлах для распространения. Есть ли способ сделать это?

new Worker(function() {
    //Long-running work here
});

Учитывая, что первоклассные функции так важны для JavaScript, почему стандартный способ выполнения фоновой работы должен загружать целый «другой» файл JavaScript с сервера?

Ответы [ 24 ]

1 голос
/ 20 июня 2016

Это просто дополнение к выше - у меня есть хорошие шаблоны для тестирования веб-работников в jsFiddle.Вместо Blob он использует jsFiddles ?js api:

function workerFN() {
  self.onmessage = function(e) {
    switch(e.data.name) {
      case "" : 
      break;
      default:
        console.error("Unknown message:", e.data.name);
    }
  }
}
// This is a trick to generate real worker script that is loaded from server
var url = "/echo/js/?js="+encodeURIComponent("("+workerFN.toString()+")()");
var worker = new Worker(url);
worker.addEventListener("message", function(e) {
  switch(e.data.name) {
    case "" : 
    break;
    default:
      console.error("Unknown message:", e.data.name);
  }
})

Обычный веб-работник и общий работник доступны шаблоны.

1 голос
/ 06 мая 2016

Так что я думаю, что у нас есть еще один классный вариант для этого, благодаря шаблонным литералам в ES6. Это позволяет нам обойтись без дополнительной рабочей функции (и ее странной области видимости) и просто написать код, предназначенный для рабочего, в виде многострочного текста, во многом как в случае, когда мы использовали для хранения текста, но без необходимости в документе или DOM сделать это в. Пример:

const workerScript = `
self.addEventListener('message', function(e) {
  var data = e.data;
  console.log('worker recieved: ',data);
  self.postMessage('worker added! :'+ addOne(data.value));
  self.close();//kills the worker
}, false);
`;

Вот сущность этого подхода .

Обратите внимание, что мы можем добавить любые дополнительные зависимости функций, которые мы хотим, в работника, просто собрав их в массив и запустив .toString для каждого из них, чтобы также сократить их до строк (должно работать, пока они функционируют) декларации), а затем просто добавив это в строку сценария. Таким образом, нам не нужно импортировать скрипты, которые мы, возможно, уже включили в объем кода, который мы пишем.

Единственный реальный недостаток этой конкретной версии заключается в том, что линтеры не смогут переворачивать код работника службы (так как это всего лишь строка), что является преимуществом для «подхода с отдельной функцией работника».

1 голос
/ 18 октября 2015

Используйте мой крошечный плагин https://github.com/zevero/worker-create

var worker_url = Worker.createURL(function(e){
  self.postMessage('Example post from Worker'); //your code here
});
var worker = new Worker(worker_url);
1 голос
/ 08 ноября 2013

здесь консоль:

var worker=new Worker(window.URL.createObjectURL(new Blob([function(){
  //Long-running work here
  postMessage('done');
}.toString().split('\n').slice(1,-1).join('\n')],{type:'text/javascript'})));

worker.addEventListener('message',function(event){
  console.log(event.data);
});
1 голос
/ 11 июня 2013

Я думаю, что лучший способ сделать это - использовать объект Blob, ниже вы можете увидеть простой пример.

// create a Blob object with a worker code
var blob = new Blob(["onmessage = function(e) { postMessage('msg from worker'); }"]);

// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);

// create a Worker
var worker = new Worker(blobURL);
worker.onmessage = function(e) {
  console.log(e.data);
};
worker.postMessage("Send some Data"); 
1 голос
/ 06 сентября 2012

Вы можете использовать веб-работников в одном и том же javascript-файле с помощью встроенных веб-работников.

Следующая статья поможет вам лучше понять веб-работников, их ограничения и отладку веб-мастеров.

Овладение веб-мастерами

1 голос
/ 14 мая 2017

Я обнаружил, что CodePen в настоящее время не выделяет синтаксис встроенных тегов <script>, которые не являются type="text/javascript" (или не имеют атрибута типа).

Поэтому я разработал аналогичное, но немного отличающееся решение, используя помеченные блоки с break, что является единственным способом, с помощью которого вы можете освободить тег <script> без создания функции-оболочки (что не нужно) .

<!DOCTYPE html>
<script id="worker1">
  worker: { // Labeled block wrapper

    if (typeof window === 'object') break worker; // Bail if we're not a Worker

    self.onmessage = function(e) {
      self.postMessage('msg from worker');
    };
    // Rest of your worker code goes here.
  }
</script>
<script>
  var blob = new Blob([
    document.querySelector('#worker1').textContent
  ], { type: "text/javascript" })

  // Note: window.webkitURL.createObjectURL() in Chrome 10+.
  var worker = new Worker(window.URL.createObjectURL(blob));
  worker.onmessage = function(e) {
    console.log("Received: " + e.data);
  }
  worker.postMessage("hello"); // Start the worker.
</script>
1 голос
/ 28 октября 2013

Попробуйте использовать jThread. https://github.com/cheprasov/jThread

// You can use simple calling like this
jThread(
    function(arr){
        //... some code for Worker
        return arr;
    }
    ,function(arr){
        //... done code
    }
)( [1,2,3,4,5,6,7] ); // some params
1 голос
/ 10 января 2014

https://developer.mozilla.org/es/docs/Web/Guide/Performance/Using_web_workers

    // Syntax: asyncEval(code[, listener])

var asyncEval = (function () {

  var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D");

  oParser.onmessage = function (oEvent) {
    if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); }
    delete aListeners[oEvent.data.id];
  };


  return function (sCode, fListener) {
    aListeners.push(fListener || null);
    oParser.postMessage({
      "id": aListeners.length - 1,
      "code": sCode
    });
  };

})();
1 голос
/ 27 января 2018

Простая обещанная версия, Function#callAsWorker, которая принимает thisArg и аргументы (как и call) и возвращает обещание:

Function.prototype.callAsWorker = function (...args) {
    return new Promise( (resolve, reject) => {
        const code = `self.onmessage = e => self.postMessage((${this.toString()}).call(...e.data));`,
            blob = new Blob([code], { type: "text/javascript" }),
            worker = new Worker(window.URL.createObjectURL(blob));
        worker.onmessage = e => (resolve(e.data), worker.terminate());
        worker.onerror = e => (reject(e.message), worker.terminate());
        worker.postMessage(args);
    });
}

// Demo
function add(...nums) {
    return nums.reduce( (a,b) => a+b );
}
// Let the worker execute the above function, with the specified arguments
add.callAsWorker(null, 1, 2, 3).then(function (result) {
    console.log('result: ', result);
});
...