修复AJAX加载文件两次但没有jQuery的问题

时间:2019-06-11 04:59:49

标签: javascript

我正在开发一个简单的Web应用程序,该应用程序需要加载16个音频文件来处理听力测试。但是我的代码两次加载文件!

应用程序必须非常轻便,快速,所以这是一个大问题。

出于同样的原因,我不想使用jQuery库。

function loadSound(array) {
    var i = 0;
    array.forEach(function(soundUrl) {
        var request = new XMLHttpRequest();
        request.open('GET', soundUrl, true);
        request.responseType = 'arraybuffer';

        request.onloadend = function() {
            var audioData = request.response;

            contextAudio.decodeAudioData(audioData, function(buffer) {
                sources[i] = contextAudio.createBufferSource();
                sources[i].buffer = buffer;
                sources[i].connect(contextAudio.destination);
                i++
            });
        };
        request.send(null);
    });
}

soundList数组和loadSound调用:

var soundList = new Array(
'http://localhost/testauditif/sons/440L.wav',
'http://localhost/testauditif/sons/440R.wav',
'http://localhost/testauditif/sons/125L.wav',
'http://localhost/testauditif/sons/125R.wav',
'http://localhost/testauditif/sons/250L.wav',
'http://localhost/testauditif/sons/250R.wav',
'http://localhost/testauditif/sons/500L.wav',
'http://localhost/testauditif/sons/500R.wav',
'http://localhost/testauditif/sons/1000L.wav',
'http://localhost/testauditif/sons/1000R.wav',
'http://localhost/testauditif/sons/2000L.wav',
'http://localhost/testauditif/sons/2000R.wav',
'http://localhost/testauditif/sons/4000L.wav',
'http://localhost/testauditif/sons/4000R.wav',
'http://localhost/testauditif/sons/8000L.wav',
'http://localhost/testauditif/sons/8000R.wav'
);

loadSound(soundList);

javascript控制台:     XHRGEThttp://localhost/testauditif/sons/440L.wav     [HTTP / 1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/440R.wav
[HTTP/1.1 200 OK 0ms]

0 script.js:88:12
XHRGEThttp://localhost/testauditif/sons/125L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/125R.wav
[HTTP/1.1 200 OK 0ms]

0 script.js:88:12
XHRGEThttp://localhost/testauditif/sons/250L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/250R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/500L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/500R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/1000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/1000R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/2000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/2000R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/4000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/4000R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/8000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/8000R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/440L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/440R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/125L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/125R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/250L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/250R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/500L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/500R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/1000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/1000R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/2000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/2000R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/4000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/4000R.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/8000L.wav
[HTTP/1.1 200 OK 0ms]

XHRGEThttp://localhost/testauditif/sons/8000R.wav
[HTTP/1.1 200 OK 0ms]

2 个答案:

答案 0 :(得分:1)

关闭!!!

让我们来看看代码发生了什么。

您开始遍历数组,每个URL在soundUrl中定义为array.forEach(function(soundUrl) {})。请注意,变量i保留在该匿名函数中,因为它是在loadSound函数中定义的。

您使用request.send(null);发送请求。在request.onloadend函数中,i的值为0。到目前为止一切正常。

现在麻烦了。在不等待调用onloadend的情况下,您移至forEach循环中的下一个soundUrl。初始化request.onloadend时,除非已经调用了先前请求的i,否则onloadend的值仍为0。 (假设音频文件需要花费一些时间才能下载到浏览器,则这种可能性很小)

在forEach循环的中间某处,您的第一个请求request.onloadend递增时会调用i

最终结果?最后,您在sources数组中出现了堆垃圾,其中下载了很少的文件,几乎没有一个文件被下一个音频文件覆盖,并且它们之间有空洞。

PS:如代码所示,它不起作用。那是真正的问题吗?也许。没有有关array包含的内容以及代码发送到后端的请求数量的进一步信息。


我建议的解决方案。

function loadSound(array) {
    array.forEach(function(soundUrl, i) {
        // No need to declare var i for iteration. Foreach provides the index.
        var request = new XMLHttpRequest();
        // Creating an instance of XMLHttpRequest inside loop to ensure 
        // request.onloadend does not get overriden in the next iteration.
        request.open('GET', soundUrl, true);
        request.responseType = 'arraybuffer';

        request.onloadend = function() {
            // Retain i inside the function using a local variable inside the callback function.
            var idx = i;
            var audioData = request.response;

            contextAudio.decodeAudioData(audioData, function(buffer) {
                // Not sure whether decodeAudioData in asyc. If so, you again need to retain idx inside the callback.
                var src_idx = idx;
                sources[src_idx] = contextAudio.createBufferSource();
                sources[src_idx].buffer = buffer;
                sources[src_idx].connect(contextAudio.destination);
            });
        };
        request.send(null);
    });
}

答案 1 :(得分:0)

请尝试是否可以解决您的问题

此版本未使用var i设置源中的内容。如果以后需要i来知道已经缓冲了多少源。只需将i的长度设为sources

const request = new XMLHttpRequest();
var sources = null;
var i = null; // only if you want to keep i 

function loadSound(array) {
    console.log(array); // only here for testing
    var sources = []; // define or re-define sources as empty array

    array.forEach(function(soundUrl) {
        request.open('GET', soundUrl, true);
        request.responseType = 'arraybuffer';

        request.onloadend = function() {
            console.log(request); // only here for testing
            var audioData = request.response;

            contextAudio.decodeAudioData(audioData, function(buffer) {
                let newsource = contextAudio.createBufferSource(); 
                // let is ES6 style it can also work without let
                newsource.buffer = buffer;
                newsource.connect(contextAudio.destination);
                sources.push(newsource); 
                // added your new source to your sources array
                var i = sources.length; 
                // if you need var i elsewhere it now contains total number of sources
                // if you don't need var i hereafter remove it from the code
                console.log(sources); // only here for testing
            });
        };
        request.send(null);
    });
}