在jquery中创建一个异步的每个循环

时间:2013-05-01 06:52:49

标签: javascript jquery asynchronous

这是我的每个循环: -

var image_obj = {};

$(".wrapper").each(function (index, data) {
  var dfile = this.getElementsByClassName('image')[0];
  file = dfile.files[0];
  if(file != null) {
    var fr = new FileReader();


fr.onload = function (e) {

          img = new Image();
          img.onload = function (k) {
            var canvas = document.createElement("canvas");
            canvas.width = img.width;
            canvas.height = img.height;
            var ctx = canvas.getContext("2d");
            ctx.drawImage(img, 0, 0);
            objindex = "obj_" + index;
            image_obj[objindex] = canvas.toDataURL("image/jpeg");

          };
          img.src = fr.result;
        };
        fr.readAsDataURL(file);
      }
    });

我需要每个循环的索引将base_64编码图像保存到对象。

但是索引没有按顺序显示,因为每个循环执行在到达canvas.getContext("2d");之前完成。

1 个答案:

答案 0 :(得分:0)

一个大问题是你需要在你的外部函数中声明img

$(".wrapper").each(function (index, data) {
  var img;

原因是,img是全球性的。在img函数中捕获的onload变量只包含该全局的当前值,这正是最近的each调用分配给它的任何内容(可能是jquery对象中的最后一个包装器) )。然后,当调用onload时,它会将错误的图像写入画布。通过声明变量,您可以确保每个外部函数作用域都有自己的img变量,以便捕获onload函数,然后在实际应用它们时使用它们。

修改如果您想确保输出的订单是正确的,那么您最后应该对其进行排序,因为您在onload运行时无法控制;这实际上是它的美丽。我做这样的事情:

ctx.drawImage(img, 0, 0);
if (typeof(image_obj.images) == "undefined")
  image_obj.images = [];
image_obj.images[index] = canvas.toDataURL("image/jpeg");

或者只是让image_obj本身成为一个数组,然后执行:

ctx.drawImage(img, 0, 0);
image_arr[index] = canvas.toDataURL("image/jpeg");

取决于您是否需要将对象作为其他东西的容器。

由于这是一个数组,而不是一个对象,因此图像将按顺序排列。

修改2

现在的问题是,如果某些文件不在那里,你会在阵列中出现漏洞。让我们不要发生这种情况:

var index = -1;
$(".wrapper").each(function (_, data) {
  ...
  if(file != null) {
    var fr = new FileReader();
    index++;
    var localIndex = index; //to capture locally

    fr.onload = function (e) {
      ...
      ctx.drawImage(img, 0, 0);
      image_arr[localIndex] = canvas.toDataURL("image/jpeg");
      ..