Home > Net >  How to await/subscribe to internal variables updating from null?
How to await/subscribe to internal variables updating from null?

Time:03-02

I'm using SpeechRecognition in the browser and I've created a speech service:

this.recognition.addEventListener('result', (e) => {
    if (e.results) {
        let result = e.results[e.resultIndex];
        console.log('Final? '   result.isFinal);
        let _transcript = result[0].transcript;
        let _confidence = result[0].confidence;
        if (result.isFinal) {
            console.log('Final result: '   _transcript);
            this.finalText = _transcript; // <---------------- FinalText updated
        } else {
            console.log('Confidence? '   _confidence);
            if (_confidence > 0.6) {
                this.finalText = _transcript;  // <---------------- FinalText updated
            }
        }
    }
});

Inside my service I have a start() function that returns a promise with the finalText string but my current method of checking if finalText was updated is just not right.

return new Promise(async (resolve, reject) => {
    let i = 0;
    for (i = 0; i < 100; i  ) {
        // Keep checking for final text to update
        if (this.finalText != null) {
            console.log('Final text submitting response');
            this.finalText = null;
            return resolve('Success');
        } else {
            console.log('waiting');
            if (this.isStoppedSpeech) { // True if we clicked stop() or if the 'end' event listener fires
                return reject('Timeout');
            }
        }
        await new Promise((r) => setTimeout(r, 500)); // sleep
    }
}).catch((error) => {
    console.error(error); // Timeout
    this.stop();
});

All I want to do is return when this.FinalText has text. I was thinking perhaps I should subscribe to it somehow and then await this.FinalText. I just need the promise to work properly.

Example usage:

this.speech.start().then((s) => {
    console.log('Done speaking');
    if (this.speech.getLastPhrase() != null)
        this.pushChat({
            speak: this.speech.getLastPhrase()
        });
});

I do not want to use setTimeout or setInterval. How can I await for this.FinalText then return the value inside of my start() function promise?

CodePudding user response:

This seems like a good use case for an RXJS subject. It is an observable from which you can emit values on demand.

Instantiate final text as a Subject and call .next() when you want to emit a value.

finalText = new Subject<string>();
    this.recognition.addEventListener('result', (e: any) => {
      if (e.results) {
        let result = e.results[e.resultIndex];
        console.log('Final? '   result.isFinal);
        let _transcript = result[0].transcript;
        let _confidence = result[0].confidence;
        if (result.isFinal) {
          console.log('Final result: '   _transcript);
          this.finalText.next(_transcript); // <---------------- FinalText updated
        } else {
          console.log('Confidence? '   _confidence);
          if (_confidence > 0.6) {
            this.finalText.next(_transcript); // <---------------- FinalText updated
          }
        }
      }
    });

You can subscribe to the Subject to execute code on each .next() call:

    this.finalText.subscribe((text) => {
      console.log('Done speaking');
      if (text)
        this.pushChat({
          speak: text,
        });
    });

you can also use Angular's async pipe to update the value in html automatically.

<p>{{ finalText | async }}</p>

You should definitely look into the rxjs library / observables. You basically made a primitive version of an observable with your start() function.

  • Related