如何使用间隔将 angular 范围绑定到 web worker 的结果?
How to bind angular scope to the result of a web worker using an interval?
我需要根据网络工作者的 "callback" 从我的范围更新一个变量。这些 web workers 基本上是 return 值在特定时间间隔的时间间隔。
这是我的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)
}
我知道如何使用 promise 从 web worker 获取结果,但正如我所料,它只适用于第一次回调。
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
};
});
我在这里错过了什么?我怎样才能 "continuously" 将变量从我的范围更新为网络工作者的结果?
Webworker 事件 onmessage
发生在 angular 上下文之外,因此 angular 摘要系统不知道要更新绑定。在这种情况下,我们需要明确地说 angular 以通过调用 $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.result = data
之后尝试 $scope().$apply()
吗?
在您的第一种情况下,AFAIK 您无法两次解决相同的承诺,这就是您没有得到预期结果的原因。我建议您采用订阅者-监听器模式来实现此 $broadcast/$emit 方法。这tutorial会给你一个好的开始。
我需要根据网络工作者的 "callback" 从我的范围更新一个变量。这些 web workers 基本上是 return 值在特定时间间隔的时间间隔。
这是我的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)
}
我知道如何使用 promise 从 web worker 获取结果,但正如我所料,它只适用于第一次回调。
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
};
});
我在这里错过了什么?我怎样才能 "continuously" 将变量从我的范围更新为网络工作者的结果?
Webworker 事件 onmessage
发生在 angular 上下文之外,因此 angular 摘要系统不知道要更新绑定。在这种情况下,我们需要明确地说 angular 以通过调用 $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.result = data
之后尝试 $scope().$apply()
吗?
在您的第一种情况下,AFAIK 您无法两次解决相同的承诺,这就是您没有得到预期结果的原因。我建议您采用订阅者-监听器模式来实现此 $broadcast/$emit 方法。这tutorial会给你一个好的开始。