HTMLAudioElement界面提供对元素属性的访问。每次请求都会有延迟从服务器获取声音。
一个基本的例子:
var flush = new Audio('hello.wav');
$(document).on('click', function() {
flush.play();
});
问题:有一个延迟(100ms +),因为每次请求(想象10个以上不同的声音)声音都需要从服务器下载,即使声音容量为30 KB。
问题:这个问题有解决方案吗?在DOM准备就绪时下载声音或使用替代方法。这是主持人/我的位置问题吗?主人是Heroku。
答案 0 :(得分:1)
您可以通过AJAX预取所有文件Blobs,然后使用blobURI直接从内存中播放它们,摆脱取出时间,但您仍然需要解码时间踢进去。
const db_url = 'https://dl.dropboxusercontent.com/s/';
const urls = ['1cdwpm3gca9mlo0/kick.mp3', 'h2j6vm17r07jf03/snare.mp3', 'kbgd2jm7ezk3u3x/hihat.mp3', 'h8pvqqol3ovyle8/tom.mp3'];
preload(urls)
.then(blobURis => {
blobURis.forEach((uri, i) => {
const btn = document.createElement('button');
btn.onclick = e => new Audio(uri).play();
btn.textContent = urls[i].split('/')[1].split('.')[0];
document.body.appendChild(btn);
});
});
function preload(urls) {
const requests = urls.map(url => fetch(db_url + url)
.then(r => r.blob()) // request as Blob
.then(b => URL.createObjectURL(b)) // get a blobURI to access from memory
);
return Promise.all(requests);
}
因此,您也可以对文件进行预解码,并且每次都为每个文件使用相同的<audio>
。
const db_url = 'https://dl.dropboxusercontent.com/s/';
const urls = ['1cdwpm3gca9mlo0/kick.mp3', 'h2j6vm17r07jf03/snare.mp3', 'kbgd2jm7ezk3u3x/hihat.mp3', 'h8pvqqol3ovyle8/tom.mp3'];
preload(urls)
.then(blobURis => {
blobURis.forEach((uri, i) => {
const audio = new Audio(uri);
audio.autoplay = false;
const btn = document.createElement('button');
btn.onclick = e => {
audio.currentTime = 0;
audio.play();
}
btn.textContent = urls[i].split('/')[1].split('.')[0];
document.body.appendChild(btn);
});
});
function preload(urls) {
const requests = urls.map(url => fetch(db_url + url)
.then(r => r.blob())
.then(b => URL.createObjectURL(b))
);
return Promise.all(requests);
}
但是当你提出要求时,你仍然不能完全确定它会开始。
所以最好绝对没有延迟就是使用Web Audio API。
const db_url = 'https://dl.dropboxusercontent.com/s/';
const urls = ['1cdwpm3gca9mlo0/kick.mp3', 'h2j6vm17r07jf03/snare.mp3', 'kbgd2jm7ezk3u3x/hihat.mp3', 'h8pvqqol3ovyle8/tom.mp3'];
const a_ctx = new (window.AudioContext || window.webkitAudioContext)();
preload(urls)
.then(audioBuffers => {
audioBuffers.forEach((buf, i) => {
const btn = document.createElement('button');
btn.onclick = e => {
const source = a_ctx.createBufferSource();
source.buffer = buf;
source.connect(a_ctx.destination);
source.start(0);
};
btn.textContent = urls[i].split('/')[1].split('.')[0];
document.body.appendChild(btn);
});
});
function preload(urls) {
const requests = urls.map(url => fetch(db_url + url)
.then(r => r.arrayBuffer()) // this time we request as ArrayBuffer
.then(b => a_ctx.decodeAudioData(b))
);
return Promise.all(requests);
}
<!-- Promising decodeAudioData for Safari https://github.com/mohayonao/promise-decode-audio-data/ [MIT] -->
<script src="https://cdn.rawgit.com/mohayonao/promise-decode-audio-data/eb4b1322/build/promise-decode-audio-data.min.js"></script>
Ps:所有示例都在ES6中并使用 fetch API以便于阅读,但在ES5和XMLHttpRequest中可以完全相同。