You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript循环获取图片高度异常:部分sizes数组元素值为0

解决JavaScript中通过for循环创建Image实例时偶尔无法获取图片高度的问题

问题描述

我通过for循环创建了40个Image实例,每个实例随机选择三个指定图片路径中的一个,然后尝试获取图片高度存入sizes数组,路径存入tests数组。大部分时候正常,但偶尔sizes里会有元素是0,无法正确获取高度。我的代码如下:

let tests = []; 
let sizes = []; 
let deger; 
for (let index = 0; index < 40; index += 1) { 
  let img = new Image(); 
  let random = Math.floor(Math.random() * 3); 
  if(random==0){ 
    deger = '/img/test-1.png'; 
    img.src = deger; 
    sizes[index]=img.height; 
    tests[index] = deger; 
  }else if(random==1){ 
    deger = '/img/test-2.png'; 
    img.src = deger; 
    sizes[index]=img.height; 
    tests[index] = deger; 
  }else{ 
    deger = '/img/test-3.png'; 
    img.src = deger; 
    sizes[index]=img.height; 
    tests[index] = deger; 
  } 
} 
console.log(sizes);

问题根源

出现这个问题的核心原因是图片加载是异步操作:当你设置img.src后,浏览器才开始向服务器请求图片资源,这时候图片还没加载完成,img.height返回的是图片元素的初始默认值0,而非图片的实际高度。

偶尔能正常获取高度是因为浏览器可能缓存了这些图片,加载速度极快,刚好在你读取img.height时完成加载,但缓存状态不可控,所以会出现偶尔失败的情况。

解决方案

我们需要等待图片完全加载完成后再获取高度,这里提供两种实用方案:

方案1:使用onload事件监听加载完成

修改代码,在图片的onload回调中获取高度并存入数组,同时处理加载失败的场景:

let tests = []; 
let sizes = []; 
let completedCount = 0;
const totalImages = 40;

for (let index = 0; index < totalImages; index += 1) { 
  let img = new Image(); 
  let random = Math.floor(Math.random() * 3); 
  let deger;

  // 用switch简化路径判断
  switch(random) {
    case 0:
      deger = '/img/test-1.png';
      break;
    case 1:
      deger = '/img/test-2.png';
      break;
    default:
      deger = '/img/test-3.png';
  }

  img.src = deger;
  tests[index] = deger;

  // 图片加载完成后再获取高度
  img.onload = function() {
    sizes[index] = img.height;
    completedCount++;
    // 所有图片加载完成后再输出结果
    if (completedCount === totalImages) {
      console.log(sizes);
      // 这里可以执行依赖图片尺寸的后续逻辑
    }
  };

  // 处理图片加载失败的情况
  img.onerror = function() {
    sizes[index] = '加载失败';
    completedCount++;
    if (completedCount === totalImages) {
      console.log(sizes);
    }
  };
}

方案2:使用Promise和Promise.all(更优雅的异步批量处理)

如果你的环境支持ES6+,可以用Promise封装图片加载逻辑,通过Promise.all等待所有图片加载完成后统一处理:

// 封装图片加载为Promise函数
function loadImage(src) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = src;
    img.onload = () => resolve({ src, height: img.height });
    img.onerror = () => reject(new Error(`加载图片失败: ${src}`));
  });
}

const totalImages = 40;
const imagePromises = [];

for (let index = 0; index < totalImages; index += 1) { 
  let random = Math.floor(Math.random() * 3); 
  let deger;

  switch(random) {
    case 0:
      deger = '/img/test-1.png';
      break;
    case 1:
      deger = '/img/test-2.png';
      break;
    default:
      deger = '/img/test-3.png';
  }

  imagePromises.push(loadImage(deger));
}

// 等待所有图片加载完成
Promise.all(imagePromises)
  .then(results => {
    const tests = results.map(item => item.src);
    const sizes = results.map(item => item.height);
    console.log('tests数组:', tests);
    console.log('sizes数组:', sizes);
    // 执行后续业务逻辑
  })
  .catch(error => {
    console.error('图片加载出错:', error);
  });

关键提醒

  • 永远不要在设置img.src后立刻读取height/width,必须等待图片加载完成。
  • 务必处理onerror事件,避免因图片加载失败导致后续逻辑卡住。
  • 使用Promise可以让异步代码更清晰,尤其适合批量处理多个异步操作的场景。

内容的提问来源于stack exchange,提问作者Reşit Abdullah Yavuzkol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:57:31