Как привязать угловую область к результату веб-работника, использующего интервал?
Мне нужно обновить переменную из моей области на основе "обратного вызова" веб-работников. Эти веб-работники в основном представляют собой интервал, который возвращает значение через определенный интервал.
Вот мой 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)
}
Я знаю, как получить результат от веб-работников, использующих обещание, но, как я и ожидал, он работает только для первого обратного вызова.
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
});
}]);
Поэтому я попытался связать результат с областью действия напрямую, чтобы посмотреть, работает ли она (что мне не понравилось, поскольку я хотел использовать фабрики для своих веб-работников).
И это не сработало. Я не знаю почему, но мой объем остается прежним, даже если console.log работает правильно.
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
};
});
Что мне здесь не хватает? Как я могу "постоянно" обновлять переменную из моей области до результатов веб-работника?
2 ответа
Событие веб-работника onmessage
происходит вне углового контекста, поэтому система углового дайджеста не имеет представления об обновлении привязок. В таком случае нам нужно явно сказать угловой, чтобы вручную запустить цикл дайджеста, вызвав $scope.$apply()
,
Скорее скажу скорее использовать $timeout
что было бы самым безопасным способом применить цикл дайджеста. потому что когда-то напрямую работает $apply
метод может вызвать digest cycle is in already progress
ошибка из-за конфликта с текущим рабочим циклом.
worker.onmessage = function (e) {
console.log(e.data) //properly displayed
$timeout(function(){
$scope.result = e.data; // never updated
});
};
Во втором случае, не могли бы вы попробовать $scope().$apply()
после $scope.result = data
?
И в первом случае, AFAIK, вы не можете выполнить одно и то же обещание дважды, и по этой причине вы не получаете ожидаемого результата. Я бы посоветовал вам воспользоваться шаблоном подписчик-слушатель для достижения этих методов $broadcast/$emit. Этот урок даст вам хорошее начало.