Javascript中使用Promise解决异步加载(图片、css、js等)

Javascript中使用Promise解决异步加载(图片、css、js等)
最新回答
山川志

2020-05-03 03:17:44

在JavaScript中,使用Promise可以更优雅地处理异步加载静态资源(如图片、CSS、JS等),避免回调地狱,提升代码可读性和可维护性。以下是具体实现方案及关键点说明:

一、基础实现:单资源加载

以图片加载为例,核心逻辑是通过Promise封装异步操作,在资源加载成功时resolve,失败时reject:

function loadImg(imgSrc) { return new Promise((resolve, reject) => { const img = new Image(); // 创建Image对象 img.src = imgSrc; // 设置图片路径 img.onload = () => { console.log(`图片加载成功: ${imgSrc}`); resolve(img); // 传递图片对象供后续使用 }; img.onerror = () => { console.error(`图片加载失败: ${imgSrc}`); reject(new Error(`Failed to load image: ${imgSrc}`)); }; });}// 使用示例loadImg('src.jpg') .then(img => { document.body.appendChild(img); // 加载成功后插入DOM }) .catch(err => { console.error('处理错误:', err.message); });

关键点

  • 使用new Image()创建图片对象,通过src属性触发加载。
  • onload和onerror分别对应成功和失败的回调。
  • resolve可传递数据(如图片对象),供后续.then()使用。
二、进阶场景:多资源并行加载

当需要同时加载多个资源时,使用Promise.all()可实现并行加载+统一处理

const imgList = ['1.jpg', '2.jpg', '3.jpg'];const promiseArray = imgList.map(src => loadImg(src));Promise.all(promiseArray) .then(images => { console.log('所有图片加载完成,数量:', images.length); images.forEach(img => document.body.appendChild(img)); }) .catch(err => { console.error('至少一张图片加载失败:', err.message); });

关键点

  • Promise.all()接收一个Promise数组,返回一个新的Promise。
  • 只有所有Promise都成功时,.then()才会执行,结果数组按原始顺序排列。
  • 任一Promise失败时,立即触发.catch(),跳过其他Promise。
三、扩展场景:混合资源加载

若需同时加载图片、CSS和JS文件,可统一封装Promise:

// 加载CSSfunction loadCSS(href) { return new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = href; link.onload = () => resolve(link); link.onerror = () => reject(new Error(`CSS加载失败: ${href}`)); document.head.appendChild(link); });}// 加载JSfunction loadJS(src) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = () => resolve(script); script.onerror = () => reject(new Error(`JS加载失败: ${src}`)); document.body.appendChild(script); });}// 并行加载混合资源Promise.all([ loadImg('1.jpg'), loadCSS('style.css'), loadJS('script.js')]) .then(() => console.log('所有资源加载完成')) .catch(err => console.error('资源加载出错:', err));四、错误处理优化
  1. 精细化错误捕获:通过Promise.allSettled()获取每个Promise的结果(成功/失败):

    Promise.allSettled(promiseArray) .then(results => { results.forEach((result, i) => { if (result.status === 'fulfilled') { console.log(`${imgList[i]} 加载成功`); } else { console.error(`${imgList[i]} 加载失败:`, result.reason.message); } }); });
  2. 重试机制:对失败的操作自动重试:

    function loadWithRetry(imgSrc, retries = 3) { return new Promise((resolve, reject) => { const attempt = () => { const img = new Image(); img.src = imgSrc; img.onload = () => resolve(img); img.onerror = () => { if (retries <= 0) reject(new Error(`重试次数耗尽: ${imgSrc}`)); else attempt(); // 递归重试 }; }; attempt(); });}
五、性能优化建议
  1. 资源预加载:通过<link rel="preload">提前告知浏览器加载关键资源。
  2. 懒加载:结合Intersection Observer API实现图片按需加载。
  3. 缓存策略:对已加载的资源缓存Promise对象,避免重复请求:const imgCache = new Map();function cachedLoadImg(src) { if (imgCache.has(src)) return imgCache.get(src); const promise = loadImg(src).then(img => { imgCache.set(src, promise); // 缓存Promise对象 return img; }); return promise;}
总结
  • 单资源加载:用Promise封装onload/onerror,替代回调函数。
  • 多资源加载:Promise.all()实现并行加载,Promise.allSettled()处理部分失败。
  • 混合资源:统一Promise接口,支持图片、CSS、JS等任意资源。
  • 错误处理:通过重试、精细化捕获提升健壮性。
  • 性能优化:缓存、预加载、懒加载等技术进一步优化体验。

通过Promise的链式调用和组合方法,可以清晰、高效地管理异步资源加载流程。