Нет никакого способа, кроме эксплойта ошибки в Firefox.
Событие не запускается, объект Worker не имеет никакого свойства, дающего нам знать, все должно просто потерпите неудачу тихо.
Единственным решением было бы переопределить оба Worker.terminate()
и DedicatedWorkerGlobalScope.close()
, чтобы они сообщали вам об этом.
Вот доказательство концепции:
class StateAwareWorker extends Worker {
constructor( ...args ) {
super( ...args );
this.terminated = false;
this.addEventListener( 'error', ( evt ) => {
if( evt.message && evt.message.endsWith( "closing" ) ) {
evt.stopImmediatePropagation(); // don't let other scripts know about it
evt.preventDefault(); // don't verbose in console
Object.defineProperty( this, "terminated", { value: true } );
}
} );
}
terminate() {
Object.defineProperty( this, "terminated", { value: true } );
Worker.prototype.terminate.call( this );
}
}
const url = generateWorkerURL();
const closing_worker = new StateAwareWorker( url );
closing_worker.postMessage( 'close' ); // closing internally
setTimeout( ()=> {
console.log( 'closed worker is terminated:', closing_worker.terminated );
}, 200 );
const terminated_worker = new StateAwareWorker( url );
terminated_worker.terminate(); // closing from here
setTimeout( ()=> {
console.log( 'terminated worker is terminated:', terminated_worker.terminated );
}, 200 );
const open_worker = new StateAwareWorker( url );
// not closing
setTimeout( ()=> {
console.log( 'keep-open worker is terminated:', open_worker.terminated );
}, 200 );
function generateWorkerURL() {
const script = document.querySelector( "[type='worker-script']" );
const blob = new Blob( [ script.textContent ], { type: "text/javascript" } );
return URL.createObjectURL( blob );
}
<script type="worker-script">
// override self.close top let the other-side know we're closing
{
const original = self.close;
self.close = () => {
setTimeout( () => original.call( self ), 0 );
throw new Error( "closing" );
};
}
// close the Worker at first message received
onmessage = () => {
self.close();
};
</script>
И для любопытных, использующих Firefox, вот "эксплойт", о котором я говорил, но не используйте его, он может не работать в несколько релизов:
// current Firefox doesn't throw a DOMException
// when the Worker holding the other PortMessage is terminated
// we can exploit this "bug" (?) to know if the Worker is terminted or not
function isTerminated( worker ) {
try {
worker.postMessage(()=>{});
return true;
}
catch(e){ return false; }
}
console.warn( 'This demo works only on Firefox' );
const worker_url = URL.createObjectURL( new Blob() );
const worker = new Worker( worker_url );
console.log( isTerminated( worker ) ); // false
worker.terminate(); // would also work if closed from inside
console.log( isTerminated( worker ) ); // true