在Windows系统上,speechSynthesis.getVoices()返回一个空数组。

26

我正在制作一个Chrome扩展程序,其中我使用了语音合成技术。当我在控制台中输入speechSynthesis.getVoices()时,会显示21种不同的语音。非常好!

但是,在我的JavaScript代码中使用console.log()打印同样的代码时,控制台返回一个空数组。我无法弄清楚问题出在哪里!


语音合成获取数据的内部数组是否可以异步填充?在 setTimeout 后尝试运行代码会发生什么? - CertainPerformance
是的,你说得对。对我来说,它在1秒的超时时间内运行良好。谢谢! - Melvin Abraham
有没有更好的方法可以使用 Promise 来完成这个任务?我尝试了下面的代码,但它仍然返回一个空数组:function set_up_speech() { return new Promise(function(resolve, reject) { var synth = window.speechSynthesis; var voices = synth.getVoices(); resolve(voices) }) } 调用方式为 set_up_speech().then(function(voices) { console.log(voices) }); - user1063287
@user1063287 因为你立即解决了承诺并返回数组,而没有检查数组voices是否填充了语音名称并且不为空,所以它返回一个空数组。 - Melvin Abraham
@MelvinAbraham,谢谢,我最终使用了这个:https://dev59.com/jGEi5IYBdhLWcg3wMp9y#51998112 - user1063287
1
@user1063287,我已经发布了自己的版本来解决这个问题。请查看一下... - Melvin Abraham
1个回答

32

正如评论中的 @CertainPerformance 所指出的那样,当页面加载时,由于异步操作,需要一定时间来填充声音数组。因此,当页面加载后立即将数组记录到控制台时,我们会看到一个空数组...

为了解决这个问题,我们可以在一定时间(比如10或50毫秒)之后将其记录到控制台:

setTimeout(() => {
    console.log(window.speechSynthesis.getVoices());
}, <time_in_ms>);

如果你想使用Promises实现相同的功能,那么这就是代码:

function setSpeech() {
    return new Promise(
        function (resolve, reject) {
            let synth = window.speechSynthesis;
            let id;

            id = setInterval(() => {
                if (synth.getVoices().length !== 0) {
                    resolve(synth.getVoices());
                    clearInterval(id);
                }
            }, 10);
        }
    )
}

let s = setSpeech();
s.then((voices) => console.log(voices));    // Or any other actions you want to take...

在这里,每个时间间隔后,我们检查getVoices()返回的voices数组是否为空。如果不是,我们最终会解析该承诺(promise)...


如果您选择这种方法,在浏览器加载语音之前引用speechSynthesis可能是必要的(我想它不会这样做,除非被认为是必要的)。您可能需要使用onvoiceschanged事件。 - Herbert Van-Vliet
我想象中应该有某种“voicesReady”或“speechSynthesisReady”事件,也许在未来,你可以监听它,而不是每隔10毫秒检查一次...这相当于蛮力。 - nonopolarity
11
当声音变化时,这段代码会在窗口上打印一条警告信息,并输出可以使用的语音列表。 - Plokko
1
最好使用onvoiceschanged事件,而不是像@Plokko所描述的使用setInterval。另请参见https://dev59.com/jGEi5IYBdhLWcg3wMp9y - Jezzamon
为什么要先让 s = setSpeech() 呢?为什么不直接使用 setSpeech().then((voices) => 呢? - Bryan

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