使用 async/await 替代回调函数在使用 Worklet 时。

4

我正在编写一个包装类,它隐藏了使用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.log(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.log(msg);
}

试图重写 HelloWorklet.requestMessage,但我无法弄清如何将 Promiseresolvethis.awNode.port.onmessage 连接起来。对我而言,代码在 this.awNode.port.postMessagethis.awNode.port.onmessage 之间的中断超出了异步操作范畴。

由于已经使用了 AudioWorklet,因此可以使用最新的ECMAScript功能,这已经打破了任何向后兼容性。

编辑

感谢 Khaled Osman 答案的第三部分,我能够将类重写为以下形式:

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);
}

1个回答

1

我认为有三件事情可以帮助你

  1. Promise 不会返回多个值,所以类似请求消息的东西一旦被实现/解决就无法再次触发,因此不适合请求/发布多个消息。对于这种情况,您可以使用 Observables 或 RxJS。

  2. 您可以使用 util.promisify 将 NodeJS 回调样式函数转换为 Promise,如下所示

const { readFile } = require('fs')
const { promisify } = require('util')
const readFilePromise = promisify(fs.readFile)

readFilePromise('test.txt').then(console.log)

或者手动创建包装函数,返回在回调中解决/拒绝的 promises。

  1. 如果要在 promise 的块之外解决 promise,可以将 resolve/reject 保存为变量,并稍后调用它们,如下所示:
class MyClass {
  requestSomething() {
    return new Promise((resolve, reject) => {
      this.resolve = resolve
      this.reject = reject
    })
  }

  onSomethingReturned(something) {
    this.resolve(something)
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接