【问题标题】:JavaScript onload and onerror not being calledJavaScript onload 和 onerror 未被调用
【发布时间】:2017-07-20 19:23:18
【问题描述】:
var images;
function preloadTrial(actor, event) {
  return new Promise(function(res) {
    var i = 0;
    images = [];
    var handler = function(resolve, reject) {
      var img = new Image;
      var source = '/static/videos/' + actor + '/' + event + '/' + i + '.png';
      img.onload = function() {
        i++;
        resolve(img);
      }
      img.onerror = function() {
        reject()
      }
      img.src = source;
    }
    var _catch = function() { res(images) }
    var operate = function(value) {
      if (value) images.push(value);
      new Promise(handler).then(operate).catch(_catch);
    }
    operate();
  })
}

function playSequence(time){
  var delta = (time - currentTime) / 1000;
  currentFrame += (delta * FPS);
  var frameNum = Math.floor(currentFrame);
  if (frameNum >= numFramesPlay) {
    currentFrame = frameNum = 0;
    return;
  }else{
    requestAnimationFrame(playSequence);
    currentImage.src = images[frameNum];
    currentTime = time;
    console.log("display"+currentImage.src);
  }
};

function rightNow() {
  if (window['performance'] && window['performance']['now']) {
    return window['performance']['now']();
  } else {
    return +(new Date());
  }
};

currentImage = document.getElementById("instructionImage");
// Then use like this
preloadTrial('examples', 'ex1').then(function(value) {
  playSequence(currentTime=rightNow());
});

我编写了一个 Javascript 函数,假设加载一个充满编号的 .png 文件的目录。但是,我事先不知道目录中的项目数。所以我做了一个函数,继续存储图像,直到源给我一个错误。但是当我运行代码时,程序甚至没有进入.onload和.onerror函数,导致死循环。

编辑:这是我当前的代码。看起来图像已正确分配并推入数组图像。但是当我尝试将其加载到 img 标签(currentImage.src)并运行 playSequence 时,它​​不会显示。

【问题讨论】:

  • 我认为 /static 正在尝试在根 (/) 目录中找到文件夹 static。文件结构设置是什么样的?将其更改为 ./staticstatic 有什么作用吗?
  • @J.陈不,那不是问题。它适用于 for 循环。我使用一段时间的唯一原因是因为我不知道图像的数量。
  • 摆脱on。它用于 HTML 而不是脚本。
  • 我认为正在发生的事情是图像[i] 不断被写入。我假设 while 循环的运行速度比图像对象加载的速度快;当您执行images[i].src = source; 时,它会尝试加载源代码,但while 循环的迭代速度更快,我们在加载源代码之前点击了images[i] = new Image();
  • 你应该使用一个promise来解决onload并拒绝onerror,然后加载下一个直到你发现错误。

标签: javascript


【解决方案1】:

您可以使用承诺来处理图像的预加载。 将解析链接到 onload 事件并拒绝 onerror 以结束循环。

function preloadImages(baseurl, extension, starter) {
  return new Promise(function(res) {
    var i = starter;
    var images = [];
    // Inner promise handler
    var handler = function(resolve, reject) {
      var img = new Image;
      var source = baseurl + i + '.' + extension;
      img.onload = function() {
        i++;
        resolve(img);
      }
      img.onerror = function() {
        reject('Rejected after '+ i + 'frames.');
      }
      img.src = source;
    }
    // Once you catch the inner promise you resolve the outer one.
    var _catch = function() { res(images) }
    var operate = function(value) {
      if (value) images.push(value);
      // Inner recursive promises chain.
      // Stop with the catch resolving the outer promise.
      new Promise(handler).then(operate).catch(_catch);
    }
    operate();
  })
}

要模拟视频播放器,您可以在 HTML5 画布上绘图。

function play(canvas, imagelist, refreshRate, frameWidth, frameHeight) {
    // Since we're using promises, let's promisify the animation too.
    return new Promise(function(resolve) {
        // May need to adjust the framerate
        // requestAnimationFrame is about 60/120 fps depending on the browser
        // and the refresh rate of the display devices.
        var ctx = canvas.getContext('2d');
        var ts, i = 0, delay = 1000 / refreshRate;
        var roll = function(timestamp) {
            if (!ts || timestamp - ts >= delay) {
                // Since the image was prefetched you need to specify the rect.
                ctx.drawImage(imagelist[i], 0, 0, frameWidth, frameHeight);
                i++;
                ts = timestamp;
            }
            if (i < imagelist.length) 
                requestAnimationFrame(roll);
            else 
                resolve(i);
        }
        roll();
    })
}

为了测试,我使用 ffmpeg 通过以下命令剪切视频:

ffmpeg -i input.mp4 -ss 00:00:14.435 -vframes 100 %d.png

我使用 devd.io 快速创建了一个包含脚本和图像以及基本 index.html 的静态文件夹。

imageroller.js - 使用上面的代码。

var preload = preloadImages('/static/videos/examples/testvid/', 'png', 1);
preload.then(function(value) {
    console.log('starting play');
    var canvas = document.getElementById("canvas");
    play(canvas, value, 24, 720, 400) // ~480p 24fps
        .then(function(frame){ 
            console.log('roll finished after ' + frame + ' frames.') 
        })
});

虽然图像的预加载速度很慢,但如果将帧数保持在可接受的水平,则可以制作一些不错的循环。

【讨论】:

  • 我的旧动画方式有什么问题,没有办法补救吗?非常感谢您的回答。
  • @AlexKer 我在使用之前没有看到 currentFrame 定义,所以当你定义 currentFrame += (delta * FPS) 时,你得到的是 NaN,但你从来没有得到你的框架。
  • 我之前确实定义过。我可以更新我的代码。但是您的代码运行良好。非常感谢!
【解决方案2】:

我还没有测试过下面的 sn-p(可能有更清洁的解决方案),但这个想法应该是正确的。基本上我们有一个递归函数loadImages(),我们传入images数组和一个回调函数。我们等待当前图像加载;如果它加载,我们将其推送到images 并再次调用loadImages()。如果它抛出一个错误,我们知道我们已经完成加载,所以我们返回我们的回调函数。如果您有任何问题,请告诉我。

function preloadTrial(actor, event) {
  let images = [];
  loadImages(images, actor, event, function () {
    // code to run when done loading
  });
};

function loadImages (images, actor, event, callback) {
  let img = new Image();
  let i = images.length;
  let source ='/static/videos/'+actor+'/'+event+'/'+i+'.png';
  img.onload = function() {
    images.push(img);
    return loadImages(images, actor, event, callback);
  }
  img.onerror = function() {
    return callback(images);
  }
  img.src = source;
}

【讨论】:

    【解决方案3】:

    最佳解决方案是提供一个服务器端 API,该 API 可以预先告诉您目录中有多少图像。 如果这不可能,您应该一个接一个地加载图像,以防止对服务器的过多请求。在这种情况下,我会将图像加载代码放在一个单独的函数中,如果前一个图像加载成功,则调用它,如下所示:

    function loadImage(actor, event, i, loadCallback, errorCallback) {
    var image = new Image();
    var source ='/static/videos/'+actor+'/'+event+'/'+i+'.png';
    image.onload = loadCallback;
    image.onerror = errorCallback;
    image.src = source;
    return image;
    }
    

    然后在你的 while 循环和 loadCallback 中调用这个函数。

    【讨论】:

      猜你喜欢
      • 2012-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-18
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      相关资源
      最近更新 更多