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

如何用Promise/async/await实现图片渲染完成后的加载状态控制?

用Promise/async/await重构图片加载逻辑,精准控制加载状态

我完全懂你的困扰——原来依赖最后一个setTimeout回调来关闭加载状态的方式太“凑活”了,根本没法保证图片真的加载并渲染完成。而且想用更清晰的Promise/async/await代替jQuery的Deferred语法,又不想大动原有DOM渲染的逻辑。下面就来一步步改造:

核心改造思路

  1. 把AJAX请求改成用await处理,替代$.when().done()
  2. 给每个图片的加载+动画过程封装成Promise,确保只有当图片真正加载完成、fadeIn动画结束后,才认为这个图片处理完毕
  3. 用for循环+await替代批量setTimeout,让逐个加载图片的逻辑更直观
  4. 在点击事件里用try/catch统一处理成功/失败场景,确保按钮状态总能恢复

改造后的完整代码

1. 点击事件改造(改成async函数)

$('#container').on('click', '#imgSearch', async function (e) {
  const $searchBtn = $(this);
  // 显示加载状态
  $searchBtn.html(`<i class="fa fa-spinner fa-spin"></i>Loading`);

  // 保留你原来的单选按钮判断逻辑,这里用占位符代替
  const search = /* 你的搜索关键词逻辑 */;
  const sort = /* 你的排序逻辑 */;
  const phpController = /* 你的接口地址 */;
  const limit = /* 数量限制 */;

  try {
    // 等待所有图片加载渲染完成
    await showImgs(search, sort, phpController, limit);
    // 恢复按钮文本
    $searchBtn.text('Search');
  } catch (error) {
    // 出错时提示并恢复按钮
    alert(error.message);
    $searchBtn.text('Search');
  }
});

2. 改造showImgs为async函数

async function showImgs(search, sort, phpController, limit) {
  imgArray = [];
  
  // 用await直接处理jQuery的AJAX请求($.post本身返回类Promise对象)
  const response = await $.post(phpController, { search, sort, limit }, { dataType: 'json' });

  if (response.error) {
    // 抛出错误,让上层try/catch处理
    throw new Error(response.error.img);
  }

  // 统一把结果转成数组,方便后续循环处理
  const imgs = Array.isArray(response) ? response : [response];

  // 逐个处理图片,每秒加载一个
  for (let i = 0; i < imgs.length; i++) {
    // 等待对应时长的延迟(和原来的setTimeout逻辑一致)
    await new Promise(resolve => setTimeout(resolve, 1000 * i));
    // 等待当前图片加载+渲染完成
    await saveAndDisplayImage(imgs[i]);
  }
}

3. 合并并改造图片处理函数(封装成async函数)

把原来的saveImages和displayImages合并,同时封装图片加载和动画完成的Promise:

async function saveAndDisplayImage(img) {
  imgArray.push(img);
  
  // 创建DOM元素
  const $imgContainer = $(`<div id='${img.id}'><img src="${img.image}"></div>`);
  const $img = $imgContainer.find('img');

  // 封装图片加载完成的Promise
  const imgLoadPromise = new Promise((resolve, reject) => {
    // 监听图片加载成功/失败
    $img.on('load', resolve);
    $img.on('error', () => reject(new Error(`图片加载失败: ${img.image}`)));
    // 处理图片已缓存的情况
    if ($img[0].complete) resolve();
  });

  // 添加到DOM并执行fadeIn,封装动画完成的Promise
  $imgContainer.hide().appendTo(imgSection);
  const fadeAnimationPromise = new Promise(resolve => $imgContainer.fadeIn(1000, resolve));

  // 等待图片加载完成 AND 动画结束,才认为这个图片处理完毕
  await Promise.all([imgLoadPromise, fadeAnimationPromise]);
}

关键细节说明

  • 为什么不用原来的alertFinished?:原来的逻辑只是等最后一个定时器触发,但图片可能还在加载、动画还没结束。现在通过Promise.all同时等待图片加载和fadeIn完成,真正做到“渲染完成后再恢复按钮”。
  • 关于DOM绘制事件的疑问:确实没有类似readystatechange的全局事件专门监听DOM绘制完成,但对于单个元素来说,我们可以通过:
    • 图片元素的load事件(监听资源加载完成)
    • jQuery动画的回调(监听视觉渲染动画结束)
    • 复杂场景下可以用requestAnimationFrame(监听浏览器下一次重绘)
      来精准判断元素是否已经完成渲染。
  • 最小改动原有逻辑:我保留了你原来的“每秒加载一个图片”“fadeIn动画”“图片数组存储”等逻辑,只是把异步部分封装成Promise,没有大改DOM渲染的代码。

内容的提问来源于stack exchange,提问作者jmoney

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:10:31