在javascript中的异步递归函数
问题描述:
我想从我的服务器流到客户端的MP3数据。我正在使用Ajax来做这件事。服务器每个请求发送50千字节。我写了两个函数:一个获取mp3数据和一个播放它们。第一个函数需要50千字节,对它们进行解码并将解码数据存储在一个数组中,然后递归地调用它自己。只要数组中的第一个元素填充数据,第二个函数就会开始播放。问题是,这只适用于第一个50千字节,然后才失败。我想要做的是保持我的get_buffer函数运行,直到服务器告诉它没有更多的数据要发送,并保持我的play()函数播放数据,直到数组中没有更多的元素。在javascript中的异步递归函数
这里是我的两个功能:
function buffer_seg() {
// starts a new request
buff_req = new XMLHttpRequest();
// Request attributes
var method = 'GET';
var url = '/buffer.php?request=buffer&offset=' + offset;
var async = true;
// set attributes
buff_req.open(method, url, async);
buff_req.responseType = 'arraybuffer';
// keeps loading until something is recieved
if (!loaded) {
change_icon();
buffering = true;
}
buff_req.onload = function() {
segment = buff_req.response;
// if the whole file was already buffered
if (segment.byteLength == 4) {
return true;
} else if (segment.byteLength == 3) {
return false;
}
// sets the new offset
if (offset == -1) {
offset = BUFFER_SIZE;
} else {
offset += BUFFER_SIZE;
}
//decodes mp3 data and adds it to the array
audioContext.decodeAudioData(segment, function(decoded) {
buffer.push(decoded);
debugger;
if (index == 0) {
play();
}
});
}
buff_req.send();
buff_seg();
}
二级功能:
function play() {
// checks if the end of buffer has been reached
if (index == buffer.length) {
loaded = false;
change_icon();
if (buffer_seg == false) {
stop();
change_icon();
return false;
}
}
loaded = true;
change_icon();
// new buffer source
var src = audioContext.createBufferSource();
src.buffer = buffer[index++];
// connects
src.connect(audioContext.destination);
src.start(time);
time += src.buffer.duration;
src.onended = function() {
src.disconnect(audioContext.destination);
play();
}
}
答
到buffer_seg
的递归调用是在buffer_seg
的主体,而不是在回调,所以它会立即发生 - 而不是像你打算的那样,在收到答复后。其次,这也意味着递归调用是无条件的,当它应该基于先前的响应是否指示更多的数据可用时。如果这不仅仅是浏览器崩溃,我不知道为什么。这也意味着大量的流式音频可能会被无序地压入缓冲区。
所以开始我会看看递归调用移动到onload
处理程序的末尾,检查流结束后。
在第二个函数中,你打算做什么if (buffer_seg == false)
?这种情况永远不会得到满足。您是否认为这是查看buffer_seg
的最后一个返回值的方法?这不是它的工作原理。也许你应该有一个变量,这两个函数都可以看到,其中buffer_seg
可以设置,play
可以测试,或类似的东西。
“offset”变量告诉服务器开始服务器发送mp3音频的哪个字节。因此,如果将偏移量发送到文件末尾或文件结束后,服务器会回复“已完成”。我检查一下arraybuffer的大小是否等于4,而不是必须“完成”。然后它返回false。对不起,这是我的不好,它应该是(buffer_seg()== false)。当它到达数组的末尾时,它调用buffer_seg()函数来查看buffer_seg是否将缓冲新数据或返回false来指示EOF。谢谢你的回复 –
是的,我知道你打算抵消什么。我不确定你为什么指出这一点;它不会改变您的代码编写过程中您的响应可能会失败。另外,'(buffer_seg()== false)'不会更好,因为调用'buffer_seg'永远不会返回。无论如何,因为你有'buffer_seg'自己调用,所以没有'play'调用它的意思。 –
是的,我同意你的观点,我可以看到这可能导致脚本无法正常运行,我甚至已经纠正了一些这些问题。但是,对于如何编写一个函数来保存流式数据并将其存储在数组中以及读取该数组并存储它的另一个函数中,您是否有任何建议?或者任何想法如何缓冲MP3二进制数据,并在整个缓冲完成之前播放它? –