Nhân viên web không có tệp Javascript riêng?


291

Theo như tôi có thể nói, nhân viên web cần phải được viết trong một tệp JavaScript riêng và được gọi như thế này:

new Worker('longrunning.js')

Tôi đang sử dụng trình biên dịch đóng để kết hợp và thu nhỏ tất cả mã nguồn JavaScript của mình và tôi không cần phải có nhân viên của mình trong các tệp riêng biệt để phân phối. Có cách nào để làm việc này không?

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

Do các hàm hạng nhất rất quan trọng đối với JavaScript, tại sao cách tiêu chuẩn để thực hiện công việc nền phải tải toàn bộ tệp JavaScript khác từ máy chủ web?


7
Đó là bởi vì việc giữ một bối cảnh thực thi hoàn toàn là các luồng an toàn thậm chí còn quan trọng hơn các hàm hạng nhất :-)
Pointy

1
Tôi đang làm việc với nó (hay đúng hơn là giảm thiểu vấn đề): DynWorker . Bạn có thể làm: var worker = new DynWorker(); worker.inject("foo", function(){...});...
Félix Saparelli


1
OP đã xóa câu hỏi "Công nhân giảng dạy để chấp nhận chức năng thay vì tệp nguồn JavaScript". Câu trả lời được đăng lại ở đây
Rob W

Tôi đã phát triển task.js để làm điều này dễ thực hiện hơn nhiều. Hầu hết thời gian bạn chỉ cố gắng giảm tải các tác vụ khóa nhỏ.
Chad Scira

Câu trả lời:


225

http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers

Điều gì sẽ xảy ra nếu bạn muốn tạo tập lệnh worker của mình một cách nhanh chóng hoặc tạo một trang độc lập mà không phải tạo các tệp worker riêng biệt? Với Blob (), bạn có thể "nội tuyến" công nhân của mình trong cùng một tệp HTML làm logic chính bằng cách tạo một điều khiển URL tới mã worker như một chuỗi


Ví dụ đầy đủ về nhân viên nội tuyến BLOB:

<!DOCTYPE html>
<script id="worker1" type="javascript/worker">
  // This script won't be parsed by JS engines because its type is javascript/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>


Giải pháp duy nhất của Google Chrome, dường như Firefox 10 sẽ hỗ trợ nó, tôi không biết về các trình duyệt khác
4esn0k

2
BlobBuiler hiện không được chấp nhận . Sử dụng Blob thay thế. Hiện được hỗ trợ trong Firefox / WebKit / Opera và IE10 mới nhất, xem các bảng tương thích cho các trình duyệt cũ hơn.
Félix Saparelli

3
Trình xây dựng Blob có thể được hỗ trợ trong IE10, nhưng bạn vẫn không thể chuyển javascript cho nhân viên web thông qua nó (thậm chí không có trong IE11): connect.microsoft.com/IE/feedback/details/801810/ .
jayarjo

1
@albanx - xét nghiệm gì? đã có hàng tỷ trang demo trực tuyến cho thấy phân luồng không làm treo trình duyệt trong nhiều năm.
vsync

2
@albanx - bạn có quan tâm ít nhất là nói trình duyệt bí truyền nào bạn sử dụng bị treo không? bản demo này có treo cho bạn không? eg.microsoft.com/testdrive/Graphics/WorkerF dãys / từ
vsync

162

Giải pháp html5rocks để nhúng mã nhân viên web trong HTML khá kinh khủng.
Và một chuỗi các chuỗi JavaScript thoát ra cũng không tốt hơn, nhất là vì nó làm phức tạp luồng công việc (Trình biên dịch đóng không thể hoạt động trên các chuỗi).

Cá nhân tôi thực sự thích các phương thức toString, nhưng @ dan-man THẬT regex!

Cách tiếp cận ưa thích của tôi:

// Build a worker from an anonymous function body
var blobURL = URL.createObjectURL( new Blob([ '(',

function(){
    //Long-running work here
}.toString(),

')()' ], { type: 'application/javascript' } ) ),

worker = new Worker( blobURL );

// Won't be needing this anymore
URL.revokeObjectURL( blobURL );

Hỗ trợ là giao điểm của ba bảng này:

Tuy nhiên, điều này sẽ không hoạt động đối với SharedWorker , vì URL phải khớp chính xác, ngay cả khi tham số 'tên' tùy chọn khớp. Đối với SharedWorker, bạn sẽ cần một tệp JavaScript riêng.


Cập nhật 2015 - Điểm kỳ dị của ServiceWorker sẽ đến

Bây giờ có một cách thậm chí còn mạnh mẽ hơn để giải quyết vấn đề này. Một lần nữa, lưu trữ mã worker dưới dạng một hàm, (chứ không phải là một chuỗi tĩnh) và chuyển đổi bằng cách sử dụng .toString (), sau đó chèn mã vào CacheStorage theo một URL tĩnh mà bạn chọn.

// Post code from window to ServiceWorker...
navigator.serviceWorker.controller.postMessage(
 [ '/my_workers/worker1.js', '(' + workerFunction1.toString() + ')()' ]
);

// Insert via ServiceWorker.onmessage. Or directly once window.caches is exposed
caches.open( 'myCache' ).then( function( cache )
{
 cache.put( '/my_workers/worker1.js',
  new Response( workerScript, { headers: {'content-type':'application/javascript'}})
 );
});

Có hai dự phòng có thể xảy ra. ObjectURL như trên, hoặc liền mạch hơn, đặt một thực tế tệp JavaScript tại /my_workers/worker1.js

Ưu điểm của phương pháp này là:

  1. SharedWorkers cũng có thể được hỗ trợ.
  2. Các tab có thể chia sẻ một bản sao được lưu trong bộ nhớ cache tại một địa chỉ cố định. Cách tiếp cận blob tăng sinh đối tượng ngẫu nhiên cho mỗi tab.

4
Khả năng tương thích trình duyệt sẽ như thế nào trên giải pháp này?
Ben Dilts

Bạn có thể giải thích về giải pháp này, nó hoạt động như thế nào? Worker1.js là gì? Có phải là một tập tin js riêng biệt? Tôi đang cố gắng sử dụng nhưng không thể làm cho nó hoạt động. Cụ thể, tôi đang cố gắng làm cho nó hoạt động cho SharedWorker
Yehuda

Nếu chỉ bạn có thể gói nó trong một chức năng hữu ích!
mmm

@ Ben Dilts: Khả năng tương thích của trình duyệt sẽ giống như chỉ chạy mã của bạn thông qua babel: babeljs.io/repl
Jack Giffin

Tiêu chuẩn không đảm bảo rằng Function.prototype.toString () trả về thân hàm dưới dạng chuỗi. Bạn có lẽ nên thêm một cảnh báo cho câu trả lời.
RD

37

Bạn có thể tạo một tệp JavaScript duy nhất nhận thức được bối cảnh thực thi của nó và có thể đóng vai trò là tập lệnh mẹ và công nhân. Hãy bắt đầu với một cấu trúc cơ bản cho một tệp như thế này:

(function(global) {
    var is_worker = !this.document;
    var script_path = is_worker ? null : (function() {
        // append random number and time to ID
        var id = (Math.random()+''+(+new Date)).substring(2);
        document.write('<script id="wts' + id + '"></script>');
        return document.getElementById('wts' + id).
            previousSibling.src;
    })();
    function msg_parent(e) {
        // event handler for parent -> worker messages
    }
    function msg_worker(e) {
        // event handler for worker -> parent messages
    }
    function new_worker() {
        var w = new Worker(script_path);
        w.addEventListener('message', msg_worker, false);
        return w;
    }
    if (is_worker)
        global.addEventListener('message', msg_parent, false);

    // put the rest of your library here
    // to spawn a worker, use new_worker()
})(this);

Như bạn có thể thấy, tập lệnh chứa tất cả mã cho cả quan điểm của cha mẹ và công nhân, kiểm tra xem cá thể riêng của nó có phải là một nhân viên không !document. Tính script_pathtoán hơi khó sử dụng được sử dụng để tính toán chính xác đường dẫn của tập lệnh so với trang mẹ, vì đường dẫn được cung cấp new Workercó liên quan đến trang mẹ chứ không phải tập lệnh.


4
Trang web của bạn dường như đã biến mất; bạn có URL mới không?
BrianFreud

1
Đây là một cách tiếp cận thú vị. FWIW, tôi phát hiện tính năng Công nhân web bằng cách kiểm tra sự hiện diện của "bản thân" (đối tượng toàn cầu của Công nhân web) so với "cửa sổ".
pwnall

Tôi đã xem xét cách PapaPude xử lý Công nhân web và họ dường như thực hiện phương pháp này github.com/mholt/PapaPude
JP DeVries

Tôi nghĩ rằng việc kiểm tra bằng cách sử dụng 'typeof importScripts! == null' có thể cho biết tập lệnh có đang chạy trong phạm vi worker không.
MeTTeO

1
Tôi không hiểu phần trước là gì từ phần tử script. Ai đó có thể giải thích cho tôi?
Teemoh

28

Sử dụng Blobphương pháp, làm thế nào về điều này cho một nhà máy công nhân:

var BuildWorker = function(foo){
   var str = foo.toString()
             .match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1];
   return  new Worker(window.URL.createObjectURL(
                      new Blob([str],{type:'text/javascript'})));
}

Vì vậy, bạn có thể sử dụng nó như thế này ...

var myWorker = BuildWorker(function(){
   //first line of worker
   self.onmessage(){....};
   //last line of worker
});

BIÊN TẬP:

Tôi vừa mở rộng ý tưởng này hơn nữa để thực hiện giao tiếp đa luồng dễ dàng hơn: Bridged-worker.js .

EDIT 2:

Các liên kết ở trên là một ý chính tôi tạo ra. Một số người khác sau đó đã biến nó thành một repo thực tế .


11

Nhân viên web hoạt động trong các bối cảnh hoàn toàn riêng biệt như các Chương trình riêng lẻ.

Điều này có nghĩa là mã không thể được di chuyển từ bối cảnh này sang bối cảnh khác ở dạng đối tượng, vì sau đó chúng có thể tham chiếu các đối tượng thông qua các bao đóng thuộc về bối cảnh khác.
Điều này đặc biệt quan trọng vì ECMAScript được thiết kế là một ngôn ngữ luồng đơn và vì nhân viên web hoạt động trong các luồng riêng biệt, nên bạn sẽ có nguy cơ thực hiện các hoạt động không an toàn luồng.

Điều này một lần nữa có nghĩa là nhân viên web cần được khởi tạo bằng mã ở dạng nguồn.

Thông số từ WHATWG nói

Nếu nguồn gốc của URL tuyệt đối kết quả không giống với nguồn gốc của tập lệnh nhập, thì hãy ném ngoại lệ SECURITY_ERR.

Do đó, tập lệnh phải là tệp bên ngoài có cùng sơ đồ với trang gốc: bạn không thể tải tập lệnh từ dữ liệu: URL hoặc javascript: URL và trang https: không thể bắt đầu nhân viên sử dụng tập lệnh có http: URL.

nhưng thật không may, nó không thực sự giải thích lý do tại sao người ta không thể cho phép truyền một chuỗi với mã nguồn cho hàm tạo.


6

cách tốt hơn để đọc cho một nhân viên nội tuyến ..

    var worker_fn = function(e) 
    {
        self.postMessage('msg from worker');            
    };

    var blob = new Blob(["onmessage ="+worker_fn.toString()], { type: "text/javascript" });

    var worker = new Worker(window.URL.createObjectURL(blob));
    worker.onmessage = function(e) 
    {
       alert(e.data);
    };
    worker.postMessage("start"); 

Những gì tôi đã làm là tôi đã tạo ra một hàm với tất cả mã worker, truyền hàm đó toString(), mở rộng cơ thể và sau đó đặt nó vào Blob. Kiểm tra câu trả lời cuối cùng, tôi có một ví dụ
Fernando Carvajal

5

Nhận phản hồi của Adria và đưa nó vào chức năng có thể sao chép hoạt động với Chrome và FF hiện tại nhưng không phải IE10 (công nhân từ blob gây ra lỗi bảo mật ).

var newWorker = function (funcObj) {
    // Build a worker from an anonymous function body
    var blobURL = URL.createObjectURL(new Blob(
        ['(', funcObj.toString(), ')()'],
        {type: 'application/javascript'}
     ));

    var worker = new Worker(blobURL);

    // Won't be needing this anymore
    URL.revokeObjectURL(blobURL);

    return worker;
}

Và đây là một ví dụ hoạt động http://jsfiddle.net/ubershmekel/YYzvr/


5

Câu trả lời gần đây (2018)

Bạn có thể sử dụng Greenlet :

Di chuyển một hàm async vào luồng riêng của nó. Một phiên bản đơn chức năng của Workerize .

Thí dụ:

import greenlet from 'greenlet'

const getName = greenlet(async username => {
  const url = `https://api.github.com/users/${username}`
  const res = await fetch(url)
  const profile = await res.json()
  return profile.name
})

console.log(await getName('developit'))

3

Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể sử dụng một cái gì đó như

task.js Giao diện đơn giản hóa để có được mã chuyên sâu CPU để chạy trên tất cả các lõi (node.js và web)

Một ví dụ sẽ là

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});

2

Hãy xem plugin vkThread. Với plugin htis, bạn có thể nhận bất kỳ chức năng nào trong mã chính của mình và thực thi nó trong một luồng (web worker). Vì vậy, bạn không cần phải tạo một "tệp nhân viên web" đặc biệt.

http://www.eslinstructor.net/vkthread/

--Vimim


1

Bạn có thể sử dụng các nhân viên web trong cùng một javascript sử dụng webworkers nội tuyến.

Bài viết dưới đây sẽ đề cập đến bạn để dễ dàng hiểu các webworkers và những hạn chế cũng như gỡ lỗi của các webworkers.

Làm chủ webworkers


1

Tôi nghĩ rằng cách tốt hơn để làm điều này là sử dụng một đối tượng Blob, bên dưới bạn có thể thấy một ví dụ đơn giản.

// 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

bảng điều khiển ở đây:

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

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

Vì vậy, tôi nghĩ rằng bây giờ chúng ta có một tùy chọn thú vị khác, nhờ vào mẫu chữ trong ES6. Điều đó cho phép chúng ta phân phối với hàm worker thêm (và phạm vi kỳ lạ của nó) và chỉ viết mã dành cho worker đó dưới dạng văn bản nhiều dòng, giống như trường hợp chúng ta đang sử dụng để lưu trữ văn bản, nhưng thực sự không cần tài liệu hoặc DOM để làm điều đó trong. Ví dụ:

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);
`;

Đây là ý chính của phần còn lại của phương pháp đó .

Lưu ý rằng chúng ta có thể kéo bất kỳ phụ thuộc hàm bổ sung nào chúng ta muốn vào worker chỉ bằng cách thu thập chúng vào một mảng và chạy .toString trên mỗi chuỗi đó để giảm chúng thành chuỗi (cũng nên hoạt động miễn là chúng là khai báo hàm) và sau đó chỉ cần thêm nó vào chuỗi script. Bằng cách đó, chúng tôi không phải nhập các bản sao mà chúng tôi có thể đã đưa vào phạm vi mã chúng tôi đang viết.

Nhược điểm thực sự duy nhất của phiên bản cụ thể này là các linters sẽ không thể nhập mã nhân viên dịch vụ (vì nó chỉ là một chuỗi), đó là một lợi thế cho "cách tiếp cận chức năng công nhân riêng biệt".


1

Đây chỉ là một bổ sung ở trên - Tôi có một mẫu đẹp để thử nghiệm nhân viên web trong jsFiddle. Thay vì Blob, nó sử dụng ?jsapi jsFiddles :

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);
  }
})

Công nhân web bình thường và các mẫu công nhân chia sẻ có sẵn.


1

Tôi phát hiện ra rằng CodePen hiện không có <script>các thẻ nội tuyến đánh dấu cú pháp không type="text/javascript"(hoặc không có thuộc tính loại).

Vì vậy, tôi nghĩ ra một giải pháp tương tự nhưng hơi khác nhau sử dụng các khối dán nhãn với break, đó là cách duy nhất bạn có thể giải cứu từ một <script>thẻ mà không cần tạo một hàm wrapper (đó là không cần thiết).

<!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

Một phiên bản được quảng cáo đơn giản Function#callAsWorker, lấy thisArg và các đối số (giống như call) và trả lại một lời hứa:

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);
});


bạn nên thêm close()phương thức để đóng móc cuộc sống nhân viên web của bạn. developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/ Lời
Shahar ー Levi

@Shahar ー Levi, closechức năng bị phản đối. Tuy nhiên, công nhân có thể bị chấm dứt . Tôi đã thêm rằng bây giờ.
trincot

0

Tôi sử dụng mã như thế này, bạn có thể định nghĩa onmessage của mình là một chức năng khác với văn bản thuần túy, vì vậy trình soạn thảo có thể làm nổi bật mã của bạn và jshint hoạt động.

const worker = createWorker();

createWorker() {
    const scriptContent = getWorkerScript();
    const blob = new Blob([
        scriptContent,
    ], {
        type: "text/javascipt"
    });
    const worker = new Worker(window.URL.createObjectURL(blob));
    return worker;
}

getWorkerScript() {
    const script = {
        onmessage: function (e) {
            console.log(e);
            let result = "Hello " + e.data
            postMessage(result);
        }
    };
    let content = "";
    for (let prop in script){
        content += `${prop}=${script[prop].toString()}`;
    }
    return content;
}


Nhìn vào câu trả lời của tôi , tôi vừa làm điều đó nhưng tôi đã viết cả một lớp để trừu tượng hóa cách vượt qua cuộc gọi lại
Fernando Carvajal

0

Có, có thể, tôi đã làm điều đó bằng cách sử dụng các tệp Blob và chuyển một cuộc gọi lại

Tôi sẽ chỉ cho bạn thấy một lớp tôi đã viết và cách nó quản lý việc thực hiện các cuộc gọi lại trong nền.

Trước tiên, bạn khởi tạo GenericWebWorkervới bất kỳ dữ liệu nào bạn muốn chuyển đến cuộc gọi lại sẽ thực hiện trong Web Worker, bao gồm các chức năng bạn muốn sử dụng, trong trường hợp này là một số, một ngày và một hàm được gọi làblocker

var worker = new GenericWebWorker(100, new Date(), blocker)

Hàm chặn này sẽ thực thi vô hạn trong khi trong n miliseconds

function blocker (ms) {
    var now = new Date().getTime();
    while(true) {
        if (new Date().getTime() > now +ms)
            return;
    }   
}

và sau đó bạn sử dụng nó như thế này

worker.exec((num, date, fnBlocker) => {
    /*Everithing here does not block the main thread
      and this callback has access to the number, date and the blocker */
    fnBlocker(10000) //All of this run in backgrownd
    return num*10

}).then(d => console.log(d)) //Print 1000

Bây giờ, thời gian để xem phép thuật trong ví dụ dưới đây

/*https://github.com/fercarvo/GenericWebWorker*/
class GenericWebWorker {
    constructor(...ags) {
        this.args = ags.map(a => (typeof a == 'function') ? {type:'fn', fn:a.toString()} : a)
    }

    async exec(cb) {
        var wk_string = this.worker.toString();
        wk_string = wk_string.substring(wk_string.indexOf('{') + 1, wk_string.lastIndexOf('}'));            
        var wk_link = window.URL.createObjectURL( new Blob([ wk_string ]) );
        var wk = new Worker(wk_link);

        wk.postMessage({ callback: cb.toString(), args: this.args });
 
        var resultado = await new Promise((next, error) => {
            wk.onmessage = e => (e.data && e.data.error) ? error(e.data.error) : next(e.data);
            wk.onerror = e => error(e.message);
        })

        wk.terminate(); window.URL.revokeObjectURL(wk_link);
        return resultado
    }

    async parallel(arr, cb) {
        var res = [...arr].map(it => new GenericWebWorker(it, ...this.args).exec(cb))
        var all = await Promise.all(res)
        return all
    }

    worker() {
        onmessage = async function (e) {
            try {                
                var cb = new Function(`return ${e.data.callback}`)();
                var args = e.data.args.map(p => (p.type == 'fn') ? new Function(`return ${p.fn}`)() : p);

                try {
                    var result = await cb.apply(this, args); //If it is a promise or async function
                    return postMessage(result)

                } catch (e) { throw new Error(`CallbackError: ${e}`) }
            } catch (e) { postMessage({error: e.message}) }
        }
    }
}


function blocker (ms) {
    var now = new Date().getTime();
    while(true) {
        if (new Date().getTime() > now +ms)
            return;
    }   
}

setInterval(()=> console.log("Not blocked " + Math.random()), 1000)

console.log("\n\nstarting blocking code in Worker\n\n")

var worker = new GenericWebWorker(100, new Date(), blocker)

worker.exec((num, date, fnBlocker) => {
    fnBlocker(7000) //All of this run in backgrownd
    return num*10    
})
.then(d => console.log(`\n\nEnd of blocking code: result ${d}\n\n`)) //Print 1000


0

Bạn có thể đặt nội dung của tệp worker.js của mình bên trong backticks (cho phép hằng chuỗi đa dòng) và tạo worker từ một blob như thế này:

var workerScript = `
    self.onmessage = function(e) {
        self.postMessage('message from worker');
    };
    // rest of worker code goes here
`;

var worker =
    new Worker(createObjectURL(new Blob([workerScript], { type: "text/javascript" })));

Điều này rất hữu ích nếu vì bất kỳ lý do gì bạn không muốn có các thẻ script riêng cho nhân viên.


0

Một giải pháp khác là chỉ bọc Công nhân trong một hàm, sau đó tạo một blob gọi hàm như vậy:

     function workerCode() {
        self.onmessage = function (e) {
          console.log("Got message from parent", e.data);
        };
        setTimeout(() => {
          self.postMessage("Message From Worker");
        }, 2000);
      }

      let blob = new Blob([
        "(" + workerCode.toString() + ")()"
      ], {type: "text/javascript"});

      // Note: window.webkitURL.createObjectURL() in Chrome 10+.
      let worker = new Worker(window.URL.createObjectURL(blob));
      worker.onmessage = function (e) {
        console.log("Received: " + e.data);
      };
      worker.postMessage("hello"); // Start the worker.

-1

Một lớp lót để chạy các chức năng trong công nhân:

const FunctionalWorker = fn => new Worker(window.URL.createObjectURL(new Blob(["(" + workerCode.toString() + ")()"], {type: "text/javascript"})));

Ví dụ sử dụng:

let fn = FunctionalWorker(() => {
    self.postMessage("hi");
});
fn.onmessage = msg => {
    console.log(msg);
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.