如何在nativescript-texttospeech中使用finished回调并排序语音消息
Hey there! Let's break down how to get your TTS messages to read in order and properly use the finishedCallback with your Vue NativeScript code.
The Core Issue
Your current code uses async/await, but without properly tying the finishedCallback to a Promise, the await won't actually wait for each speech to finish—meaning all three messages might try to play at once or out of order. We need to wrap the TTS call in a Promise that resolves only when the finishedCallback fires.
Fixed Code with Explanations
Here's the updated version of your component that solves both problems:
<template> <Page> <ActionBar title="Speak Promises Component" /> <StackLayout> <Label :text="currentText" col="0" row="0" /> <Button text="start" @tap="start" /> </StackLayout> </Page> </template> <script> import { TNSTextToSpeech, SpeakOptions } from "nativescript-texttospeech"; const TTS = new TNSTextToSpeech(); export default { data() { return { currentText: " ", // Keep reusable options separate to avoid repetition baseSpeakOptions: { locale: "en-GB" } }; }, methods: { async start() { // Now each await will wait for the previous speech to finish await this.talk("First message"); await this.talk("Second message"); await this.talk("Last message"); console.log("All messages have been read!"); }, talk(message) { this.currentText = message; // Wrap the TTS call in a Promise to enable async/await return new Promise((resolve) => { const speakOptions = { ...this.baseSpeakOptions, text: message, // finishedCallback is a function that runs when speech ends finishedCallback: () => { console.log(`Done reading: "${message}"`); resolve(); // Resolve the Promise to signal we're ready for the next message } }; TTS.speak(speakOptions); }); } } }; </script> <style scoped> </style>
Key Details
1. What to pass to finishedCallback?
The finishedCallback expects a zero-argument function (() => void). It triggers automatically when the TTS finishes speaking the current text. In our code, we use it to resolve the Promise, which tells await that it's safe to move to the next talk() call.
2. How does this enforce sequential speech?
By wrapping each TTS.speak() call in a Promise, we turn the callback-based API into something async/await can work with. The await will pause execution until the Promise resolves—only when the finishedCallback fires does that happen, ensuring one message finishes before the next starts.
Bonus: Error Handling
If you want to catch TTS errors (like unsupported locales or speech failures), add an errorCallback and reject the Promise:
talk(message) { this.currentText = message; return new Promise((resolve, reject) => { const speakOptions = { ...this.baseSpeakOptions, text: message, finishedCallback: resolve, errorCallback: (error) => { console.error("TTS failed:", error); reject(error); } }; TTS.speak(speakOptions); }); }
Then update your start method to handle errors:
async start() { try { await this.talk("First message"); await this.talk("Second message"); await this.talk("Last message"); console.log("All messages read successfully!"); } catch (err) { console.error("Speech failed at some point:", err); } }
Why Your Original Code Didn't Work
The original TTS.speak() call likely doesn't return a Promise that waits for the speech to finish—it probably resolves as soon as the speech starts. By adding the Promise wrapper tied to finishedCallback, we make sure await waits for the right moment.
内容的提问来源于stack exchange,提问作者Cem Kaan

