JavaScript onload和onerror未被调用

时间:2017-07-20 19:23:18

标签: javascript

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时,它不会显示。

3 个答案:

答案 0 :(得分:1)

您可以使用promises来处理图像的预加载。 将on resolves链接到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.') 
        })
});

虽然图像的预加载非常慢,但如果将帧数保持在可接受的水平,则可以制作一些漂亮的循环。

答案 1 :(得分:0)

我还没有测试下面的代码段(并且可能有更清晰的解决方案),但这个想法应该是正确的。基本上我们有一个递归函数{' ': 'h', '4': 'y', '>': '8', 'a': 'c', 'o': 'u'} ,我们传入loadImages()数组和一个回调函数。我们等待加载当前图像;如果它加载,我们将其推入images并再次调用images。如果它抛出错误,我们知道我们已经完成加载,所以我们返回我们的回调函数。如果您有任何问题,请告诉我。

loadImages()

答案 2 :(得分:0)

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

private static int dsSize(DataSet ds)
    {
        int returnValue = 0;

        foreach (DataRow dr in ds.Tables[ds.Tables.Count - 1].Rows)
        {
            int rowSize = 0;
            for (int i = 0; i < ds.Tables[ds.Tables.Count - 1].Columns.Count; i++)
            {
                rowSize += System.Runtime.InteropServices.Marshal.SizeOf(dr[i]);
            }
            returnValue += rowSize;
        }

        return returnValue;
    }

然后在while循环和loadCallback中调用此函数。