2012-07-06 26 views
25

Chúng ta có thể sử dụng người lao động web HTML5 như thế này:Tại sao Công nhân Web không thể gọi trực tiếp chức năng?

var worker = new Worker('worker.js'); 

nhưng tại sao chúng ta không thể gọi một chức năng như thế này?

var worker = new Worker(function(){ 
    //do something 
}); 
+2

Một plugin khác có thể giúp bạn là [vkThread] (http://www.eslinstructor.net/vkthread/). Hãy xem [http://www.eslinstructor.net/vkthread/](http://www.eslinstructor.net/vkthread/) Bạn sẽ tìm thấy các ví dụ và tài liệu ở đó. – vadimk

+0

Bạn cần sử dụng URL nhưng một số trình duyệt sẽ cho phép bạn sử dụng URL BLOB. Xem [this] (http://stackoverflow.com/a/6454685/19676) câu trả lời cho một ví dụ. – Maurice

+0

Như @Qix cho biết trong một ý kiến ​​đóng góp khác, vkThread cũng dựa trên function.toString, mang lại sự không thống nhất giữa các trình duyệt. –

Trả lời

17

Đây là cách công nhân web được thiết kế. Họ phải có tệp JS bên ngoài riêng của họ và môi trường của riêng họ được khởi tạo bởi tệp đó. Họ không thể chia sẻ một môi trường với không gian JS toàn cầu thông thường của bạn vì các lý do xung đột đa luồng.

Một lý do khiến người lao động web không được phép truy cập trực tiếp vào biến toàn cầu của bạn là nó sẽ yêu cầu đồng bộ hóa luồng giữa hai môi trường không phải là thứ sẵn có (và nó sẽ làm phức tạp những thứ phức tạp). Khi công nhân web có các biến toàn cục riêng biệt của họ, họ không thể gây rối với chuỗi JS chính ngoại trừ hàng đợi nhắn tin được đồng bộ hóa chính xác với chuỗi JS chính. Có lẽ một ngày nào đó, các lập trình viên JS tiên tiến hơn sẽ có thể sử dụng các kỹ thuật đồng bộ hóa luồng truyền thống để chia sẻ quyền truy cập vào các biến chung, nhưng bây giờ tất cả các giao tiếp giữa hai luồng phải đi qua hàng đợi thông báo và nhân viên web không thể truy cập môi trường của luồng Javascript chính.

+0

đã đồng ý, chúng tôi có thời gian nhưng đã đi cùng. –

+0

Tôi nghĩ rằng javascript là Single-threaded.But các broswer có thể mở và chạy các trang với Multi-ren. Vì vậy, tôi đoán nhân viên web tạo một trang mới (hoặc gọi nó là môi trường mới) và chạy tập lệnh trong đó? Vì vậy, nhân viên web chỉ có thể gọi một tệp JS bên ngoài. – Dozer

+0

@ Dzer - đó là cơ bản chính xác. Các chủ đề javascript chính là đơn luồng và nhiều mã javascript trên web giả định rằng. Thay vì thêm các công cụ đồng bộ hóa luồng nâng cao để cho phép đa luồng chung, những người thiết kế web quyết định thực hiện một bước nhỏ hơn và cho phép một luồng mới, nhưng CHỈ nếu nó khởi tạo môi trường toàn cầu của riêng nó thông qua một tệp JS mới và không thể chia sẻ bất kỳ truy cập toàn cục nào với chủ đề chính trừ khi được đồng bộ hóa thông qua hàng đợi tin nhắn. Điều này ngăn chặn các vấn đề đồng bộ hóa biến toàn cục giữa các luồng. – jfriend00

8

Câu hỏi này đã được hỏi before, nhưng đối với một số lý do, OP đã quyết định xóa nó.
Tôi đăng lại câu trả lời của mình, trong trường hợp người ta cần một phương pháp để tạo một nhân viên Web từ một hàm.


Trong this post, ba cách được hiển thị để tạo một công nhân Web từ một chuỗi tùy ý. Trong câu trả lời này, tôi đang sử dụng phương pháp thứ ba, vì nó được hỗ trợ trong tất cả các môi trường.

Một tập tin helper là cần thiết:

// Worker-helper.js 
self.onmessage = function(e) { 
    self.onmessage = null; // Clean-up 
    eval(e.data); 
}; 

Trong Worker thực tế của bạn, tập tin helper này được sử dụng như sau:

// Create a Web Worker from a function, which fully runs in the scope of a new 
// Worker 
function spawnWorker(func) { 
    // Stringify the code. Example: (function(){/*logic*/}).call(self); 
    var code = '(' + func + ').call(self);'; 
    var worker = new Worker('Worker-helper.js'); 
    // Initialise worker 
    worker.postMessage(code); 
    return worker; 
} 

var worker = spawnWorker(function() { 
    // This function runs in the context of a separate Worker 
    self.onmessage = function(e) { 
     // Example: Throw any messages back 
     self.postMessage(e.data); 
    }; 
    // etc.. 
}); 
worker.onmessage = function() { 
    // logic ... 
}; 
worker.postMessage('Example'); 

Lưu ý rằng phạm vi được tách nghiêm ngặt. Các biến chỉ có thể được chuyển qua và sử dụng worker.postMessageworker.onmessage. Tất cả các tin nhắn là structured clones.

+0

Giả định 'Function.toString()' hoạt động như một trình giải mã un-eval, không phải là trường hợp trong một số môi trường nhất định. Sử dụng cẩn thận! – Qix

+0

@Qix Nhận xét của bạn sẽ hữu ích hơn nếu bạn có thể đặt tên cho ít nhất một trình duyệt phổ biến nơi Web Worker được hỗ trợ, nhưng 'toString()' trên một hàm do người dùng định nghĩa không trả về một nguồn tương đương với hàm theo mặc định. –

+0

Trình duyệt không phải là môi trường Javascript duy nhất. Thực tế của vấn đề là điều này chống lại tiêu chuẩn W3C, cũng như các tiêu chuẩn Ecmascript (các chức năng không được giải mã; môi trường hỗ trợ nó là tính năng bổ sung cho mục đích gỡ lỗi). – Qix

3

Câu trả lời này có thể hơi muộn, nhưng tôi đã viết thư viện để đơn giản hóa việc sử dụng nhân viên web và nó có thể phù hợp với nhu cầu của OP.Check it out: https://github.com/derekchiang/simple-worker

Nó cho phép bạn làm điều gì đó như:

SimpleWorker.run({ 
    func: intensiveFunction, 
    args: [123456], 
    success: function(res) { 
    // do whatever you want 
    }, 
    error: function(err) { 
    // do whatever you want 
    } 
}) 
+0

Điều này trông khá giống với bài viết vkThread của @ vadimk ở trên - rõ ràng là các dự án khác nhau, tuy nhiên tôi có thể nói rằng vkThread hoạt động tốt và có nhiều phương pháp khác nhau để sử dụng. – Nick

0

Chỉ cần sử dụng plugin nhỏ của tôi https://github.com/zevero/worker-create

và làm

var worker_url = Worker.create(function(e){ 
    self.postMessage('Example post from Worker'); //your code here 
}); 
var worker = new Worker(worker_url); 
1

Trong khi nó không phải là tối ưu và nó được được đề cập trong các ý kiến, một tập tin bên ngoài là không cần thiết nếu trình duyệt của bạn hỗ trợ blobURL cho Web Worker. HTML5Rocks là inspiration cho mã của tôi:

function sample(e) 
{ 
    postMessage(sample_dependency()); 
} 

function sample_dependency() 
{ 
    return "BlobURLs rock!"; 
} 

var blob = new Blob(["onmessage = " + sample + "\n" + sample_dependency]); 
var blobURL = window.URL.createObjectURL(blob); 
var worker = new Worker(blobURL); 

worker.onmessage = function(e) 
{ 
    console.log(e.data); 
}; 

worker.postMessage(""); 

Hãy cẩn thận:

  • Các công nhân blob sẽ không sử dụng thành công các liên kết URL. Liên kết HTML5Rocks bao gồm điều này nhưng nó không phải là một phần của câu hỏi ban đầu.

  • Mọi người đã báo cáo sự cố khi sử dụng URL Blob với Công nhân web. Tôi đã thử nó với IE11 (bất cứ thứ gì được vận chuyển với FCU), MS Edge 41.16299 (Bản cập nhật của người tạo mùa thu), Firefox 57 và Chrome 62. Không có đầu mối nào đối với hỗ trợ Safari. Những cái tôi đã thử nghiệm đã hoạt động.

  • Lưu ý rằng "mẫu" và "sample_dependency" tài liệu tham khảo trong các cuộc gọi constructor Blob ngầm gọi Function.prototype.toString() như sample.toString()sample_dependency.toString(), mà là rất khác nhau vì gọi toString(sample)toString(sample_dependency).

Được đăng bởi vì đây là luồng xếp chồng đầu tiên xuất hiện khi tìm kiếm cách sử dụng Công nhân trên web mà không yêu cầu tệp bổ sung.

Nhìn vào câu trả lời của Zevero và mã trong repo của anh ấy xuất hiện tương tự. Nếu bạn thích một wrapper sạch, đây là khoảng những gì mã của mình không.

Cuối cùng - tôi là một noob ở đây vì vậy mọi chỉnh sửa đều được đánh giá cao.

Các vấn đề liên quan