Асинхронные рекурсивные функции в JavaScript
Я пытаюсь передавать данные в формате mp3 со своего сервера на клиентскую сторону. Я делаю это с помощью Ajax. Сервер отправляет 50 килобайт за запрос. Я написал две функции: одну для получения данных в формате mp3 и одну для их воспроизведения. Первая функция занимает 50 килобайт, декодирует их и сохраняет декодированные данные в массиве, а затем рекурсивно вызывает себя. Вторая функция начинает воспроизводиться, как только первый элемент в массиве заполняется данными. Проблема состоит в том, что это работает для первых 50 килобайт только тогда, когда это терпит неудачу. Я хочу, чтобы моя функция get_buffer работала до тех пор, пока сервер не скажет ей больше не отправлять данные, а моя функция play() воспроизводит данные до тех пор, пока в массиве не останется больше элементов.
Вот мои две функции:
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();
}
}
1 ответ
Рекурсивный вызов buffer_seg
находится в основной части buffer_seg
, не в обратном вызове, поэтому это происходит немедленно - нет, как вы, вероятно, намереваетесь, после получения ответа. Во-вторых, это также означает, что рекурсивный вызов является безусловным, когда он должен основываться на том, указывал ли предыдущий ответ больше данных. Если это не просто сбой вашего браузера, я не уверен почему. Это также означает, что фрагменты потокового аудио могут быть вставлены в буфер не по порядку.
Итак, для начала я бы посмотрел на перемещение рекурсивного вызова в конец onload
обработчик, после проверки на конец потока.
Во 2-й функции, что вы собираетесь if (buffer_seg == false)
сделать? Это условие никогда не будет выполнено. Вы думаете, что это способ увидеть последнее возвращаемое значение из buffer_seg
? Это не так, как это работает. Возможно, у вас должна быть переменная, которую могут видеть обе функции, которая buffer_seg
можно установить и play
можно проверить или что-то в этом роде.