Я пишу класс-оболочку, скрывающий внутренности работы с AudioWorklet. Работа с ворклетом включает в себя связь между узлом и процессором через порты сообщений.
Как только код, работающий в узле, достигает port.postMessage(), выполнение скрипта в узле завершается. Когда node.port.onmessage срабатывает (через processor.port.postMessage), код в узле может возобновить выполнение.
Я могу заставить его работать, используя функцию обратного вызова. См. код ниже.
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.info(msg);
}
const requestMessage = () => {
helloNode.requestMessage(showMessage);
}
и процессор
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);
Вызов requestMessage() приводит к тому, что Hello world! печатается в консоли. Поскольку использование обратных вызовов иногда снижает читабельность кода, я хотел бы переписать код, используя await, например:
async requestMessage = () => {
let msg = await helloNode.requestMessage;
// additional processing
console.info(msg);
}
Пытаясь переписать HelloWorklet.requestMessage, я не могу понять, как приклеить resolvePromise к this.awNode.port.onmessage. Мне кажется, что прерывание кода между this.awNode.port.postMessage и this.awNode.port.onmessage выходит за рамки асинхронности.
Поскольку использование AudioWorklet уже нарушает обратную совместимость, можно использовать последние функции ECMAScript.
редактировать
Благодаря части 3 ответа Халеда Османа я смог переписать класс следующим образом:
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.info(msg);
}



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, есть три вещи, которые могут вам помочь
Обещания не возвращают несколько значений, поэтому что-то вроде сообщения запроса не может быть запущено снова после его выполнения/разрешения, поэтому оно не подходит для запроса/отправки нескольких сообщений. Для этого вы можете использовать Observables или RxJS.
Вы можете использовать util.promisify для преобразования функций стиля обратного вызова NodeJS в такие промисы
const { readFile } = require('fs')
const { promisify } = require('util')
const readFilePromise = promisify(fs.readFile)
readFilePromise('test.txt').then(console.info)
или вручную создавать функции-оболочки, которые возвращают промисы вокруг них, которые разрешают/отклоняют внутри обратных вызовов.
class MyClass {
requestSomething() {
return new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
})
}
onSomethingReturned(something) {
this.resolve(something)
}
}