2013-05-23 25 views
68

Làm thế nào để angularJS có thể sử dụng công nhân web để chạy các tiến trình trong nền? Có mô hình nào tôi nên làm theo không?AngularJS và nhân viên web

Hiện tại, tôi đang sử dụng dịch vụ có mô hình trong một nhân viên web riêng biệt. Dịch vụ này triển khai các phương pháp như:

ClientsFacade.calculateDebt(client1); //Just an example.. 

Trong quá trình triển khai, phương pháp này sẽ gửi thông báo đến người lao động với dữ liệu. Điều này cho phép tôi trừu tượng một thực tế là nó đang được thực hiện trong một chủ đề riêng biệt và tôi cũng có thể cung cấp một triển khai thực hiện các truy vấn đối với một máy chủ hoặc thậm chí một hành động thực hiện hành động này trong cùng một luồng.

Vì tôi mới sử dụng javascript và tôi chỉ tái chế kiến ​​thức mà tôi có từ các nền tảng khác, tôi tự hỏi liệu đây có phải là thứ bạn sẽ làm hay có lẽ là Angular. . Điều này cũng giới thiệu một sự thay đổi trong kiến ​​trúc của tôi vì người lao động phải đẩy mạnh các thay đổi đối với bộ điều khiển, sau đó cập nhật các giá trị của nó và sau đó điều này được phản ánh trong khung nhìn, tôi có đang nghiên cứu kỹ hơn không? Đó là một chút bực bội rằng công nhân web "bảo vệ" tôi rất nhiều từ screwing lên bằng cách không cho phép tôi để chia sẻ bộ nhớ, vv

Trả lời

92

Giao tiếp với công nhân Web xảy ra thông qua một cơ chế nhắn tin. Chặn các tin nhắn này xảy ra trong một cuộc gọi lại. Trong AngularJS, vị trí tốt nhất để đưa một nhân viên web vào một dịch vụ khi bạn lưu ý đúng. Cách tốt nhất để giải quyết vấn đề này là sử dụng các lời hứa, mà Angular hoạt động một cách đáng kinh ngạc.

Dưới đây là một ví dụ về một webworker trong một service

var app = angular.module("myApp",[]); 

app.factory("HelloWorldService",['$q',function($q){ 

    var worker = new Worker('doWork.js'); 
    var defer = $q.defer(); 
    worker.addEventListener('message', function(e) { 
     console.log('Worker said: ', e.data); 
     defer.resolve(e.data); 
    }, false); 

    return { 
     doWork : function(myData){ 
      defer = $q.defer(); 
      worker.postMessage(myData); // Send data to our worker. 
      return defer.promise; 
     } 
    }; 

}); 

Bây giờ bất cứ điều gì ngoài thực thể truy cập dịch vụ Hello World không cần phải quan tâm đến các chi tiết thi hành HelloWorldService-HelloWorldService có thể có thể xử lý dữ liệu qua một web worker, trên http hoặc xử lý ngay tại đó.

Hy vọng điều này có ý nghĩa.

+3

gì là ** doWork.js ** trong ** var nhân = new Worker ('doWork.js'); **? – acudars

+2

Đây là tham chiếu đến tệp js bên ngoài chứa mã cho công nhân web. – ganaraj

+0

Tôi làm cách nào để tham chiếu một tệp có các tuyến đường góc? Ngay bây giờ nó phải và async tải kịch bản từ máy chủ của tôi. Tôi có thể lưu trữ ngay trên máy khách không? –

10

Tôi tìm thấy một ví dụ hoàn toàn làm việc của người lao động web trong góc here

webworker.controller('webWorkerCtrl', ['$scope', '$q', function($scope, $q) { 

    $scope.workerReplyUI; 
    $scope.callWebWorker = function() { 
     var worker = new Worker('worker.js'); 
     var defer = $q.defer(); 
     worker.onmessage = function(e) { 
      defer.resolve(e.data); 
      worker.terminate(); 
     }; 

     worker.postMessage("http://jsonplaceholder.typicode.com/users"); 
     return defer.promise; 
    } 

    $scope.callWebWorker().then(function(workerReply) { 
     $scope.workerReplyUI = workerReply; 
    }); 

}]); 

Nó sử dụng hứa hẹn sẽ chờ đợi cho người lao động để trả về kết quả.

+3

Trang web lưu trữ ví dụ này không còn khả dụng nữa. Đây là liên kết lưu trữ https://web.archive.org/web/20150709233911/http://www.codingterminal.com/articles/092014/1/XMLHttpRequest%20using%20AngularJS%20Promises%20and%20HTML5%20Web%20Workers. php –

15

Một câu hỏi rất thú vị! Tôi tìm thấy các đặc điểm kỹ thuật công nhân web một chút khó xử (có lẽ vì lý do tốt, nhưng vẫn còn khó xử). Sự cần thiết phải giữ mã công nhân trong một tệp riêng biệt làm cho ý định của một dịch vụ khó đọc và giới thiệu các phụ thuộc vào các URL tệp tĩnh trong mã ứng dụng góc của bạn. Vấn đề này có thể được giảm nhẹ bằng cách sử dụng URL.createObjectUrl() có thể được sử dụng để tạo URL cho chuỗi JavaScript. Điều này cho phép chúng tôi chỉ định mã công nhân trong cùng một tệp tạo công nhân.

var blobURL = URL.createObjectURL(new Blob([ 
    "var i = 0;//web worker body" 
], { type: 'application/javascript' })); 
var worker = new Worker(blobURL); 

Nhân viên đặc tả web cũng giữ người lao động và chính bối cảnh chủ đề hoàn toàn riêng biệt để ngăn chặn những tình huống đã bế tắc và livelocks vv có thể xảy ra. Nhưng nó cũng có nghĩa là bạn sẽ không có quyền truy cập vào các dịch vụ góc của bạn trong công nhân mà không có một số không quan trọng. Người lao động thiếu một số thứ mà chúng ta (và góc cạnh) mong đợi khi thực thi JavaScript trong trình duyệt, như biến toàn cục "tài liệu" vv.

var window = self; 
self.history = {}; 
var document = { 
    readyState: 'complete', 
    cookie: '', 
    querySelector: function() {}, 
    createElement: function() { 
     return { 
      pathname: '', 
      setAttribute: function() {} 
     }; 
    } 
}; 

Một số tính năng rõ ràng sẽ không hoạt động, liên kết với DOM. Tuy nhiên, khung tiêm và ví dụ dịch vụ $ http sẽ hoạt động tốt, đó có thể là điều chúng tôi muốn trong công nhân. Những gì chúng tôi đạt được bằng cách này là chúng tôi có thể chạy các dịch vụ góc tiêu chuẩn trong một công nhân. Do đó, chúng tôi có thể kiểm tra các dịch vụ được sử dụng trong công nhân giống như chúng tôi sẽ làm với bất kỳ sự phụ thuộc góc nào khác.

tôi đã thực hiện một bài đăng mà trau chuốt thêm một chút về here này và tạo ra một repo github mà tạo ra một dịch vụ mà thực hiện những ý tưởng thảo luận ở trên here

+0

Đối với góc> = v1.5.7, hãy suy nghĩ để thêm self.Node = {prototype: []}; xem https: // github.com/FredrikSandell/angular-workers/issues/15 – Adavo

6

Worker Web góc với ví dụ bỏ phiếu

Khi bạn giao dịch với người lao động trong AngularJS, nó thường yêu cầu kịch bản công nhân của bạn phải nội tuyến (trong trường hợp bạn đang sử dụng một số công cụ xây dựng như gulp/grunt) và chúng tôi có thể đạt được điều này bằng cách sử dụng phương pháp sau đây.

Ví dụ dưới đây cũng cho thấy cách bỏ phiếu có thể được thực hiện để máy chủ sử dụng lao động:

Đầu tiên cho phép tạo nhà máy công nhân của chúng tôi:

module.factory("myWorker", function($q) { 
    var worker = undefined; 
    return { 
     startWork: function(postData) { 
      var defer = $q.defer(); 
      if (worker) { 
       worker.terminate(); 
      } 

      // function to be your worker 
      function workerFunction() { 
       var self = this; 
       self.onmessage = function(event) { 
        var timeoutPromise = undefined; 
        var dataUrl = event.data.dataUrl; 
        var pollingInterval = event.data.pollingInterval; 
        if (dataUrl) { 
         if (timeoutPromise) { 
          setTimeout.cancel(timeoutPromise); // cancelling previous promises 
         } 

         console.log('Notifications - Data URL: ' + dataUrl); 
         //get Notification count 
         var delay = 5000; // poller 5sec delay 
         (function pollerFunc() { 
          timeoutPromise = setTimeout(function() { 
           var xmlhttp = new XMLHttpRequest(); 
           xmlhttp.onreadystatechange = function() { 
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 
             var response = JSON.parse(xmlhttp.responseText); 
             self.postMessage(response.id); 
             pollerFunc(); 
            } 
           }; 
           xmlhttp.open('GET', dataUrl, true); 
           xmlhttp.send(); 
          }, delay); 
         })(); 
        } 
       } 
      } 
      // end worker function 

      var dataObj = '(' + workerFunction + ')();'; // here is the trick to convert the above fucntion to string 
      var blob = new Blob([dataObj.replace('"use strict";', '')]); // firefox adds user strict to any function which was blocking might block worker execution so knock it off 

      var blobURL = (window.URL ? URL : webkitURL).createObjectURL(blob, { 
       type: 'application/javascript; charset=utf-8' 
      }); 

      worker = new Worker(blobURL); 
      worker.onmessage = function(e) { 
       console.log('Worker said: ', e.data); 
       defer.notify(e.data); 
      }; 
      worker.postMessage(postData); // Send data to our worker. 
      return defer.promise; 
     }, 
     stopWork: function() { 
      if (worker) { 
       worker.terminate(); 
      } 
     } 
    } 
}); 

Tiếp từ cuộc gọi điều khiển của chúng tôi nhà máy công nhân:

var inputToWorker = { 
    dataUrl: "http://jsonplaceholder.typicode.com/posts/1", // url to poll 
    pollingInterval: 5 // interval 
}; 

myWorker.startWork(inputToWorker).then(function(response) { 
    // complete 
}, function(error) { 
    // error 
}, function(response) { 
    // notify (here you receive intermittent responses from worker) 
    console.log("Notification worker RESPONSE: " + response); 
}); 

Bạn có thể gọi myWorker.stopWork(); bất kỳ lúc nào để chấm dứt công nhân khỏi bộ điều khiển của bạn!

này được thử nghiệm trong IE11 + và FF và Chrome

+0

@ChanuSukamo điều này không được gọi. Và bạn đã bỏ lỡ pollingInterval nó không được sử dụng ở bất cứ đâu. – IamStalker

1

bạn cũng có thể có một cái nhìn tại Plugin góc https://github.com/vkiryukhin/ng-vkthread

cho phép bạn thực hiện một chức năng trong một thread riêng biệt. sử dụng cơ bản:

/* function to execute in a thread */ 
function foo(n, m){ 
    return n + m; 
} 

/* create an object, which you pass to vkThread as an argument*/ 
var param = { 
     fn: foo  // <-- function to execute 
     args: [1, 2] // <-- arguments for this function 
    }; 

/* run thread */ 
vkThread.exec(param).then(
    function (data) { 
     console.log(data); // <-- thread returns 3 
    } 
); 

Các ví dụ và API doc: http://www.eslinstructor.net/ng-vkthread/demo/

--Vadim

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