JQuery和XHR请求异步问题

时间:2017-09-06 07:08:48

标签: javascript jquery html asynchronous

我正在设法为每个使用Google Chrome扩展程序找到音乐网址的div应用生成的音频图形图像。

但是,从网址下载音乐并处理图像的过程需要足够的时间让所有图像继续应用到最后一个div。

我正在尝试将图像应用到每个div中,就像整个JQuery的每个请求一样。所有div都有/renderload.gif gif播放,但只有最后一个div闪烁,因为图像逐个处理完毕。

例如,对于所有1,2,3,4,5

,src被设置为/renderload.gif

但是一旦下载了声音blob并生成了图像,只有4-5个图像会获得图像并继续加载队列,重复该问题。

以下是我正在尝试处理的一个例子。 enter image description here

这是我最近尝试通过一次加载所有音频来添加排队以避免延迟,但似乎问题仍然存在。

// context.js
function Queue(){
  var queue  = [];
  var offset = 0;
  this.getLength = function(){
    return (queue.length - offset);
  }
  this.isEmpty = function(){
    return (queue.length == 0);
  }
  this.setEmpty = function(){
    queue = [];
    return true;
  }
  this.enqueue = function(item){
    queue.push(item);
  }
  this.dequeue = function(){
    if (queue.length == 0) return undefined;
    var item = queue[offset];
    if (++ offset * 2 >= queue.length){
      queue  = queue.slice(offset);
      offset = 0;
    }
    return item;
  }
  this.peek = function(){
    return (queue.length > 0 ? queue[offset] : undefined);
  }
}


var audioqueue=new Queue();
var init=0;
var current=0;
var finished=0;


function RunGraphs(x) {
    if (x==init) {
        if (audioqueue.isEmpty()==false) {
            current++;
            var das=audioqueue.dequeue();
            var divparent=das.find(".original-image");
            var songurl=das.find(".Mpcs").find('span').attr("data-url");
            console.log("is song url "+songurl);
            console.log("is data here "+divparent.attr("title"));
            divparent.css('width','110px');
            divparent.attr('src','https://i.pinimg.com/originals/a4/f2/cb/a4f2cb80ff2ae2772e80bf30e9d78d4c.gif');
            var blob = null;
            var xhr = new XMLHttpRequest(); 
            xhr.open("GET",songurl,true); 
            xhr.responseType = "blob";//force the HTTP response, response-type header to be blob
            xhr.onload = function() {
                blob = xhr.response;//xhr.response is now a blob object
                console.log(blob);
                SCWFRobloxAudioTool.generate(blob, {
                    canvas_width: 110,
                    canvas_height: 110,
                    bar_width: 1,
                    bar_gap : .2,
                    wave_color: "#ecb440",
                    download: false,
                    onComplete: function(png, pixels) {
                        if (init == x) {
                            divparent.attr('src',png);
                            finished++;
                        }
                    }
                }); 
            }
            xhr.send();
            OnHold(x);
        }
    }
}
function OnHold(x) {
    if (x==init) {
        if (current > finished+7) {
            setTimeout(function(){
                OnHold(x)
            },150)
        } else {
            RunGraphs(x)
        }
    }
}
if (window.location.href.includes("/lib?Ct=DevOnly")){
    functionlist=[];
    current=0;
    finished=0;
    init++;
    audioqueue.setEmpty();
    $(".CATinner").each(function(index) {
        (function(x){
            audioqueue.enqueue(x);
        }($(this)));
    });
    RunGraphs(init);
};

SCWFAudioTool来自这个github存储库。 Soundcloud Waveform Generator

来自搜索请求的Queue.js,略微修改为具有setEmpty支持。Queue.js

2 个答案:

答案 0 :(得分:1)

请阅读帖子的编辑部分

我疯了一个可用的最小代码示例,以便检查你的队列和延迟方法。似乎没有我能找到的错误(我没有html文件,也无法检查丢失的文件。请自行将if (this.status >= 200 && this.status < 400)检查添加到onload回调中):

&#13;
&#13;
// context.js
function Queue(){
  var queue  = [];
  var offset = 0;
  this.getLength = function(){
    return (queue.length - offset);
  }
  this.isEmpty = function(){
    return (queue.length == 0);
  }
  this.setEmpty = function(){
    queue = [];
    return true;
  }
  this.enqueue = function(item){
    queue.push(item);
  }
  this.dequeue = function(){
    if (queue.length == 0) return undefined;
    var item = queue[offset];
    if (++ offset * 2 >= queue.length){
      queue  = queue.slice(offset);
      offset = 0;
    }
    return item;
  }
  this.peek = function(){
    return (queue.length > 0 ? queue[offset] : undefined);
  }
}


var audioqueue=new Queue();
var init=0;
var current=0;
var finished=0;


function RunGraphs(x) {
    if (x==init) {
        if (audioqueue.isEmpty()==false) {
            current++;
            var songurl = audioqueue.dequeue();
            
            console.log("is song url "+songurl);
            var blob = null;
            var xhr = new XMLHttpRequest(); 
            xhr.open("GET",songurl,true);
            xhr.responseType = "blob";//force the HTTP response, response-type header to be blob
            xhr.onload = function() {
                
                if (this.status >= 200 && this.status < 400) {
                    blob = xhr.response;//xhr.response is now a blob object
                    console.log('OK');
                    finished++;
                } else {
                    console.log('FAIL');
                }
            }
            xhr.send();
            OnHold(x);
        }
    }
}
function OnHold(x) {
    if (x==init) {
        if (current > finished+7) {
            setTimeout(function(){
                OnHold(x)
            },150)
        } else {
            RunGraphs(x)
        }
    }
}

var demoObject = new Blob(["0".repeat(1024*1024*2)]); // 2MB Blob
var demoObjectURL = URL.createObjectURL(demoObject);
if (true){
    functionlist=[];
    current=0;
    finished=0;
    init++;
    audioqueue.setEmpty();
    for(var i = 0; i < 20; i++)
        audioqueue.enqueue(demoObjectURL);
    RunGraphs(init);
};
&#13;
&#13;
&#13;

因此,如果没有关于丢失文件的错误,我可以想到的唯一错误与SCWFRobloxAudioTool.generate方法有关。

请检查回调是否被正确触发,并且在转换过程中没有产生错误。

如果您提供其他附加信息,数据或代码,我可以查看此问题。

编辑:

我查看了SoundCloudWaveform&#39;程序,我想我看到了问题:

模块不能同时处理多个查询(只有一个全局设置对象。因此,每次尝试向api添加另一个查询都会覆盖前一个查询的回调,因为fileReader是异步调用只会执行最新添加的回调。)

请考虑使用此api的oop尝试:

&#13;
&#13;
window.AudioContext = window.AudioContext || window.webkitAudioContext;

Array.prototype.max = function() {
  return Math.max.apply(null, this);
};

function SoundCloudWaveform (){

	this.settings = {
		canvas_width: 453,
		canvas_height: 66,
		bar_width: 3,
		bar_gap : 0.2,
		wave_color: "#666",
		download: false,
		onComplete: function(png, pixels) {}
	}

	this.generate = function(file, options) {

		// preparing canvas
		this.settings.canvas = document.createElement('canvas');
		this.settings.context = this.settings.canvas.getContext('2d');

		this.settings.canvas.width = (options.canvas_width !== undefined) ? parseInt(options.canvas_width) : this.settings.canvas_width;
		this.settings.canvas.height = (options.canvas_height !== undefined) ? parseInt(options.canvas_height) : this.settings.canvas_height;

		// setting fill color
		this.settings.wave_color = (options.wave_color !== undefined) ? options.wave_color : this.settings.wave_color;

		// setting bars width and gap
		this.settings.bar_width = (options.bar_width !== undefined) ? parseInt(options.bar_width) : this.settings.bar_width;
		this.settings.bar_gap = (options.bar_gap !== undefined) ? parseFloat(options.bar_gap) : this.settings.bar_gap;

		this.settings.download = (options.download !== undefined) ? options.download : this.settings.download;

		this.settings.onComplete = (options.onComplete !== undefined) ? options.onComplete : this.settings.onComplete;

		// read file buffer
		var reader = new FileReader();
        var _this = this;
        reader.onload = function(event) {
	          var audioContext = new AudioContext()
            audioContext.decodeAudioData(event.target.result, function(buffer) {
                audioContext.close();
                _this.extractBuffer(buffer);
            });
        };
        reader.readAsArrayBuffer(file);
	}

	this.extractBuffer = function(buffer) {
	    buffer = buffer.getChannelData(0);
	    var sections = this.settings.canvas.width;
	    var len = Math.floor(buffer.length / sections);
	    var maxHeight = this.settings.canvas.height;
	    var vals = [];
	    for (var i = 0; i < sections; i += this.settings.bar_width) {
	        vals.push(this.bufferMeasure(i * len, len, buffer) * 10000);
	    }

	    for (var j = 0; j < sections; j += this.settings.bar_width) {
	        var scale = maxHeight / vals.max();
	        var val = this.bufferMeasure(j * len, len, buffer) * 10000;
	        val *= scale;
	        val += 1;
	        this.drawBar(j, val);
	    }

	    if (this.settings.download) {
	    	this.generateImage();
	    }
	    this.settings.onComplete(this.settings.canvas.toDataURL('image/png'), this.settings.context.getImageData(0, 0, this.settings.canvas.width, this.settings.canvas.height));
	    // clear canvas for redrawing
	    this.settings.context.clearRect(0, 0, this.settings.canvas.width, this.settings.canvas.height);
    },

    this.bufferMeasure = function(position, length, data) {
        var sum = 0.0;
        for (var i = position; i <= (position + length) - 1; i++) {
            sum += Math.pow(data[i], 2);
        }
        return Math.sqrt(sum / data.length);
    },

    this.drawBar = function(i, h) {

    	this.settings.context.fillStyle = this.settings.wave_color;

		var w = this.settings.bar_width;
        if (this.settings.bar_gap !== 0) {
            w *= Math.abs(1 - this.settings.bar_gap);
        }
        var x = i + (w / 2),
            y = this.settings.canvas.height - h;

        this.settings.context.fillRect(x, y, w, h);
    },

    this.generateImage = function() {
    	var image = this.settings.canvas.toDataURL('image/png');

    	var link = document.createElement('a');
    	link.href = image;
    	link.setAttribute('download', '');
    	link.click();
    }
}

console.log(new SoundCloudWaveform());
&#13;
&#13;
&#13;

还要考虑简单地为队列使用数组:

&#13;
&#13;
function Queue(){
  var queue  = [];
  var offset = 0;
  this.getLength = function(){
    return (queue.length - offset);
  }
  this.isEmpty = function(){
    return (queue.length == 0);
  }
  this.setEmpty = function(){
    queue = [];
    return true;
  }
  this.enqueue = function(item){
    queue.push(item);
  }
  this.dequeue = function(){
    if (queue.length == 0) return undefined;
    var item = queue[offset];
    if (++ offset * 2 >= queue.length){
      queue  = queue.slice(offset);
      offset = 0;
    }
    return item;
  }
  this.peek = function(){
    return (queue.length > 0 ? queue[offset] : undefined);
  }
}

var q = new Queue();
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
console.log(q.dequeue());
console.log(q.dequeue());
console.log(q.dequeue());
console.log(q.dequeue());


var q2 = [];
q2.push(1)
q2.push(2)
q2.push(3)
console.log(q2.shift());
console.log(q2.shift());
console.log(q2.shift());
console.log(q2.shift());
&#13;
&#13;
&#13;

它可以防止混淆,在你的应用程序中,它的加速很小。

答案 1 :(得分:0)

在xhr对象的open方法上,将参数设置为true,同样...尝试使用onload()而不是onloadend()。祝你好运!

var xmlhttp = new XMLHttpRequest(),
method = 'GET',
url = 'https://developer.mozilla.org/';

xmlhttp.open(method, url, true);
xmlhttp.onload = function () {
// Do something with the retrieved data
};
xmlhttp.send();