Reputation: 43
I'm writing a wrapper class hiding the internals of working with AudioWorklet
. Working with a worklet involves communication between a node and a processor through message ports.
As soon as the code running in the node reaches port.postMessage()
, script execution in the node ends. When node.port.onmessage
fires (through processor.port.postMessage
), code in the node can resume execution.
I can get it to work by using a callback function. See the code below.
class HelloWorklet {
constructor(audioContext) {
audioContext.audioWorklet.addModule('helloprocessor.js').then(() => {
this.awNode = new AudioWorkletNode(audioContext, 'hello-processor');
this.awNode.port.onmessage = (event) => {
switch (event.data.action) {
case 'response message':
this.respondMessage(event.data);
break;
}
}
});
}
requestMessage = (callback) => {
this.awNode.port.postMessage({action: 'request message'});
this.callback = callback;
}
respondMessage = (data) => {
// some time consuming processing
let msg = data.msg + '!';
this.callback(msg);
}
}
let audioCtx = new AudioContext();
let helloNode = new HelloWorklet(audioCtx);
const showMessage = (msg) => {
// additional processing
console.log(msg);
}
const requestMessage = () => {
helloNode.requestMessage(showMessage);
}
and the processor
class HelloProcessor extends AudioWorkletProcessor {
constructor() {
super();
this.port.onmessage = (event) => {
switch (event.data.action) {
case 'request message':
this.port.postMessage({action: 'response message', msg: 'Hello world'});
break;
}
}
}
process(inputs, outputs, parameters) {
// required method, but irrelevant for this question
return true;
}
}
registerProcessor('hello-processor', HelloProcessor);
Calling requestMessage()
causes Hello world!
to be printed in the console. As using callbacks sometimes decreases the readability of the code, i'd like to rewrite the code using await
like so:
async requestMessage = () => {
let msg = await helloNode.requestMessage;
// additional processing
console.log(msg);
}
Trying to rewrite the HelloWorklet.requestMessage
I cannot figure out how to glue the resolve
of the Promise
to the this.awNode.port.onmessage
. To me it appears as if the interruption of the code between this.awNode.port.postMessage
and this.awNode.port.onmessage
goes beyond a-synchronicity.
As using the AudioWorklet
already breaks any backwards compatibility, the latest ECMAScript features can be used.
edit
Thanks to part 3 of the answer of Khaled Osman I was able to rewrite the class as follows:
class HelloWorklet {
constructor(audioContext) {
audioContext.audioWorklet.addModule('helloprocessor.js').then(() => {
this.awNode = new AudioWorkletNode(audioContext, 'hello-processor');
this.awNode.port.onmessage = (event) => {
switch (event.data.action) {
case 'response message':
this.respondMessage(event.data);
break;
}
}
});
}
requestMessage = () => {
return new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
this.awNode.port.postMessage({action: 'request message'});
})
}
respondMessage = (data) => {
// some time consuming processing
let msg = data.msg + '!';
this.resolve(msg);
}
}
let audioCtx = new AudioContext();
let helloNode = new HelloWorklet(audioCtx);
async function requestMessage() {
let msg = await helloNode.requestMessage();
// additional processing
console.log(msg);
}
Upvotes: 4
Views: 581
Reputation: 1467
I think there're three things that might help you
Promises don't return multiple values, so something like request message can not be fired again once its fulfilled/resolved, so it won't be suitable to request/post multiple messages. For that you can use Observables or RxJS
You can use util.promisify
to convert NodeJS callback style functions to promises like so
const { readFile } = require('fs')
const { promisify } = require('util')
const readFilePromise = promisify(fs.readFile)
readFilePromise('test.txt').then(console.log)
or manually create wrapper functions that return promises around them that resolve/reject inside the callbacks.
class MyClass {
requestSomething() {
return new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
})
}
onSomethingReturned(something) {
this.resolve(something)
}
}
Upvotes: 1