I need to update a variable from my scope based on the "callback" of web workers. These web workers are basically an interval that return value at a specific interval.
Here is my worker.js
var timer = false;
var onmessage = function (e) {
var value = e.data[0];
var stock = e.data[1];
var interval = e.data[2];
if (timer) {
clearInterval(timer);
}
timer = setInterval(function () {
stock += value;
postMessage(stock);
}, interval)
}
I know how to get the result from web workers using a promise but, as I expected, it only works for the first callback.
app.factory('workerServices', ['$q', function ($q) {
var worker = new Worker('worker.js'),
defer = $q.defer();
worker.onmessage = function (e) {
console.log('Result worker:' + e.data); //displayed each "interval"
defer.resolve(e.data);
}
return {
increment: function (value, stock, interval) {
defer = $q.defer();
worker.postMessage([value, stock, interval]);
return defer.promise;
}
};
}]);
app.controller('mainCtrl', ['$scope', 'workerServices', function ($scope, workerServices) {
var value = 1,
stock = 0,
interval = 300;
workServices.increment(val, stock, interval).then(function (newStock) {
$scope.stock = newStock; //updated once
});
}]);
So I tried to bind the result to the scope directly to see if it works (which I didn't like since I wanted to use factories for my web workers).
And it didn't work. I don't know why but my scope stay the same even if the console.log works properly.
app.controller('mainCtrl', function ($scope) {
var value = 1,
stock = 0,
interval = 300;
var worker = new Worker('worker.js');
worker.postMessage([value, stock, interval]);
worker.onmessage = function (e) {
console.log(e.data) //properly displayed
$scope.result = e.data; // never updated
};
});
What am I missing here? How can I can "continuously" update a variable from my scope to the results of a web worker?
Webworker event onmessage
is happening outside angular context, so angular digest system doesn't have any idea about to update bindings. In such case we need to explicitly say angular to kick off digest cycle manually by calling $scope.$apply()
.
Rather I'd say rather use $timeout
which would be the safest way to apply digest cycle. because sometime directly running $apply
method can cause an digest cycle is in already progress
error by conflicting with currently running cycle.
worker.onmessage = function (e) {
console.log(e.data) //properly displayed
$timeout(function(){
$scope.result = e.data; // never updated
});
};