This timing class wired from a Web Worker does not retain context for the BroadcastChannels postMessage() method. When in use it throws a error:
Uncaught TypeError: this.channel.postMessage is not a function
The error occurs when the emit() method calls the postMessage() method. Upon checking in the debugger, I can confirm that the this.channel object injected into the constructor is a valid BroadcastChannel instance and is also valid within the emit() method, as it contains the postMessage() method. However, despite these valid conditions, the error is still thrown.
I am using an arrow function so the this
would respect the parent (FoozleTimer class) of the setInterval(); however it does not seem to work.
Here is the timing class, please note the .startTimer() and .emit() methods:
class FoozleTimer {
timerInterval:any;
channel:BroadcastChannel;
/**
* Construct
*/
constructor(channel:BroadcastChannel) {
this.timerInterval = null;
this.channel = channel;
}
/**
* Time interval callback function
*/
emit() {
this.channel.postMessage({countBy:1})
console.log('emit')
return '';
}
startTimer(intervalTime = 1000) {
this.timerInterval = setInterval(() => this.emit(), intervalTime);
}
stopTimer() {
clearInterval(this.timerInterval);
}
getTimer() {
return this.timerInterval;
}
}
export default FoozleTimer;
Here the Web Worker where this timer is called:
const channel = new BroadcastChannel('channel2');
const controls = new BroadcastChannel('controls');
// Pass the Broadcast Channel into the timer
const FT = new FoozleTimer(channel);
FT.startTimer(1000);
const timer = FT.getTimer();
controls.onmessage = (event) => {
if(event && event.data.msg == 'kill-timer') {
FT.stopTimer();
console.log('killed timer')
}
}
The web worker is called like this in an index.html file:
const worker = new Worker("./TimerWorker2.js", { type: "module" });
Can you provide any insights as to why this wrong and potential ways to resolve it?
I was able to fix this by using a closure instead of of the emit() method. I then set the context of this to a parameter self and can use this inside the closure. I also wrapped the BroadCast channel into a class wrapper so its' context couldn't change.
Here is the new timer class:
And here is the BroadcastService:
I will try to refactor the BroadcastService to not have the coupled BroadcastChannel(name) and instead inject a BroadcastChannel instance.
I hope this helps someone else