如何在Javascript中预加载声音?

56

我可以轻松地通过 onload 函数预加载图像,但是用于音频的不起作用。Chrome、Safari、Firefox等浏览器不支持在音频标签中使用 onload 函数。

如何在Javascript中预加载声音而不使用JS库和不使用或创建HTML标记?


2
我所知道的唯一方法是使用一个带有对声音的引用的<embed>,将其保持不可见并禁用自动播放。但如果您不想添加HTML,我不确定还有什么其他建议。--编辑:我知道您不想要一个库,但这个可能值得检查(大小为10K):http://www.schillmania.com/projects/soundmanager2/ - Brad Christie
1
谢谢Brad,但是SoundManager使用Flash! - Manuel Ignacio López Quintero
6个回答

50

你的问题是Audio对象不支持“load”事件。

相反,有一个被称为“canplaythrough”的事件,虽然它并没有完全加载,但足够多的内容已经加载,以至于在当前下载速率下,它将在曲目足够播放的时间内完成加载。

因此,不要使用

audio.onload = isAppLoaded;

尝试

audio.oncanplaythrough = isAppLoaded;

或者更好的方法.. ;)

audio.addEventListener('canplaythrough', isAppLoaded, false);

谢谢Tylermwashburn!终于你找到了解决方案!它对我有用!非常感谢! :-) - Manuel Ignacio López Quintero
@Manuel Ignacio López Quintero:我猜这只能在HTML5中使用,无论如何,如果你想走这条路,阅读这篇文章可能会对你有所帮助http://bit.ly/ebZH3Z。 - Luca Filosofi
2
@tylermwashburn 为什么addEventListener更好? - kiewic
好的解决方案,但对于慢速连接存在问题,因为它的预测非常愚蠢。 - salmatron
说实话,我真的无法理解这个事实:我无法检测到SoundJS是否完成了所有文件的加载!比如当所有文件都加载完成时调用onComplete()方法? - Neon Warge
显示剩余2条评论

10

我尝试了tylermwashburn的被接受的答案,但它在Chrome中不起作用。所以我继续创建了这个,并且它受益于jQuery。它还会探测ogg和mp3支持。默认为ogg,因为一些专家说192KBS的ogg文件和320KBS的MP3一样好,所以你可以节省40%的音频下载量。然而,IE9需要mp3。

// Audio preloader

$(window).ready(function(){
  var audio_preload = 0;
  function launchApp(launch){
    audio_preload++;
    if ( audio_preload == 3 || launch == 1) {  // set 3 to # of your files
      start();  // set this function to your start function
    }
  }
  var support = {};
  function audioSupport() {
    var a = document.createElement('audio');
    var ogg = !!(a.canPlayType && a.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''));
    if (ogg) return 'ogg';
    var mp3 = !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
    if (mp3) return 'mp3';
    else return 0;
  }
  support.audio = audioSupport();
  function loadAudio(url, vol){
    var audio = new Audio();
    audio.src = url;
    audio.preload = "auto";
    audio.volume = vol;
    $(audio).on("loadeddata", launchApp);  // jQuery checking
    return audio;
  }
  if (support.audio === 'ogg') {
    var snd1 = loadAudio("sounds/sound1.ogg", 1);  // ie) the 1 is 100% volume
    var snd2 = loadAudio("sounds/sound2.ogg", 0.3);  // ie) the 0.3 is 30%
    var snd3 = loadAudio("sounds/sound3.ogg", 0.05);
        // add more sounds here
  } else if (support.audio === 'mp3') { 
    var snd1 = loadAudio("sounds/sound1.mp3", 1);
    var snd2 = loadAudio("sounds/sound2.mp3", 0.3);
    var snd3 = loadAudio("sounds/sound3.mp3", 0.05);
        // add more sounds here
  } else {
    launchApp(1);  // launch app without audio
  }

// this is your first function you want to start after audio is preloaded:
  function start(){
     if (support.audio) snd1.play();  // this is how you play sounds
  }

});
此外:这里有一个mp3转ogg的转换器:http://audio.online-convert.com/convert-to-ogg。或者您可以使用VLC媒体播放器进行转换。通过右键单击mp3文件(在Windows中),并查看文件详细信息来检查mp3比特率。在为新的"ogg"文件选择新比特率时,尝试将其减少40%。转换器可能会报错,因此请继续增加大小,直到被接受。当然,要测试声音是否满意的质量。此外(我也遇到过这个问题),如果您正在使用VLC媒体播放器测试音轨,请确保将音量设置在100%以下,否则您将听到音频退化,并可能错误地认为它是压缩的结果。

非常有帮助,谢谢!就音频转换而言,我实际上对Audacity非常满意(相对而言,因为它是一个免费工具)。它提供批处理功能,并且比在线工具快得多(理论上),因为它是本地程序。http://audacity.sourceforge.net/ - Mike
另外,iOS不支持OGG。 - The Onin

0
//Tested on Chrome, FF, IE6

function LoadSound(filename) {
    var xmlhttp;
    if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else { // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            document.getElementById("load-sound").innerHTML = '<embed src="' + filename + '" controller="1" autoplay="0" autostart="0" />';
        }
    }
    xmlhttp.open("GET", filename, true);
    xmlhttp.send();
}

参考资料


我认为最好的选择是第二个链接中提供的解决方案。但它使用了JQuery。难道没有更自然的方法吗? - Manuel Ignacio López Quintero
自然的方式添加 ;) 让我知道。 - Luca Filosofi
好的,我会尝试这段代码!虽然我认为管理声音和图像一样难。为什么谷歌、Mozilla、微软不像他们对待图片那样实现预加载呢? - Manuel Ignacio López Quintero
我尝试了你的解决方案,但对我来说不起作用,因为我必须创建嵌入标签。我需要仅使用JS。感谢您的努力,ASeptik! - Manuel Ignacio López Quintero

0
根据您的目标浏览器,设置audio标签上的prelaod属性可能是足够的。

0
Remy提出了一个针对iOS的解决方案,利用了精灵概念。

http://remysharp.com/2010/12/23/audio-sprites/

不确定它是否直接涉及预加载,但它有一个优点,那就是你只需要加载一个音频文件(我想这也是一个缺点)。


谢谢DA,但这并没有什么用! - Manuel Ignacio López Quintero

0

你尝试过使用ajax请求文件吗?只有在文件完全加载完成后,你才会显示/使用它。

例如:jQuery:如何预加载声音?(你不必使用jQuery)。


是的,如果没有其他选择,我想我会使用这个解决方案。我不想使用JQuery。 - Manuel Ignacio López Quintero

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