Асинхронные рекурсивные функции в 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 можно проверить или что-то в этом роде.

Другие вопросы по тегам