AngularJS和networking工作者
angularJS如何使用web worker在后台运行进程? 这样做有什么模式吗?
目前,我正在使用一个在单独的networking工作者有模型的服务。 这个服务实现如下的方法:
ClientsFacade.calculateDebt(client1); //Just an example..
在实现中,这个方法用数据发送一条消息给worker。 这使我能够抽象出它在一个单独的线程中执行的事实,并且我还可以提供一个针对服务器甚至是在同一个线程中执行此操作的实现。
由于我是新来的JavaScript,我只是从其他平台回收知识我不知道这是你会做什么,或者Angular这是我正在使用,提供了一种这样做的方式。 同时这也引入了我的架构的变化,因为工作人员必须将更改显式地推送给控制器,控制器然后更新其值,然后这反映在视图中,我是否过度工程? networking工作者不让我共享内存等,“保护”我不会因为搞砸而感到有点沮丧。
与Web工作人员的沟通通过消息传递机制进行。 拦截这些消息发生在callback中。 在AngularJS中,正如你所指出的那样,放置networking工作者的最佳位置正在服务中。 处理这个问题的最好的方法就是使用Angular的惊人的承诺。
这是一个service
中的webworker
的例子
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; } }; });
现在,任何访问Hello World服务的外部实体都不需要关心HelloWorldService
的实现细节 – HelloWorldService
可能可能通过web worker
处理数据,通过http
或者在那里进行处理。
希望这是有道理的。
一个非常有趣的问题! 我觉得networking工作者的规范有点尴尬(可能是出于很好的原因,但仍然尴尬)。 需要将工作代码保存在单独的文件中,这使得服务的意图很难读取,并且在angular度应用程序代码中引入了对静态文件URL的依赖关系。 使用可用于为JavaScriptstring创buildURL的URL.createObjectUrl()可以缓解此问题。 这允许我们在创buildworker的同一个文件中指定worker代码。
var blobURL = URL.createObjectURL(new Blob([ "var i = 0;//web worker body" ], { type: 'application/javascript' })); var worker = new Worker(blobURL);
Web工作者规范还保持工作人员和主线程上下文完全分离,以防止出现死锁和活锁等情况。 但是这也意味着你将无法在工人身上获得angular度服务。 在浏览器中执行JavaScript时,员工缺乏一些我们(和angular度)期望的东西,比如全局variables“document”等。通过在工作人员中“嘲笑”这些所需的浏览器function,我们可以运行angular色。
var window = self; self.history = {}; var document = { readyState: 'complete', cookie: '', querySelector: function () {}, createElement: function () { return { pathname: '', setAttribute: function () {} }; } };
有些function显然不能工作,绑定到DOM等,但注入框架,例如$ HTTP服务将工作得很好,这可能是我们在工作人员想要的。 我们从中获得的是,我们可以在工作人员中运行标准的angular度服务。 因此,我们可以像使用其他angular度依赖一样单位testing工作人员使用的服务。
我在这里做了一个更详细的介绍,并创build了一个github回购,创build一个实现上面讨论的想法的服务
我在这里find了Angular Web工作者的一个完整的工作例子
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; }); }]);
它使用承诺等待工作人员返回结果。
有轮询例子的angular度Web工作者
当你正在和AngularJS中的工作人员打交道时,经常需要你的工作脚本是内联的(比如你正在使用一些构build工具,例如gulp / grunt),我们可以用下面的方法来实现。
以下示例还显示了如何使用工作人员对服务器进行轮询:
先让我们创build我们的工人工厂:
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(); } } } });
接下来从我们的控制器调用工人工厂:
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); });
你可以调用myWorker.stopWork();
任何时候从你的控制器终止工人!
这在IE11 +和FF和Chrome中进行了testing
你也可以看看angular插件https://github.com/vkiryukhin/ng-vkthread
它允许你在一个单独的线程中执行一个函数。 基本用法:
/* 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 } );
示例和API文档: http : //www.eslinstructor.net/ng-vkthread/demo/
–Vadim