如何在程序运行前预创建图片并在image.onload外完成canvas绘制?
解决方案
原有代码问题
- 函数没有主动返回Image实例,调用
createImage得到的返回值是undefined,无法用于绘制 onload是异步触发的回调函数,它的返回值不会被外层createImage接收,没有实际作用- 函数内部的
image变量没有声明关键字,会意外污染全局作用域 new Image()写错为newImage(),缺少空格会触发语法错误
实现思路
你看到的可以直接用返回值绘制的用法,本质是先完成所有图片预加载,再执行绘制逻辑,不需要把绘制代码写在onload里的核心是:调用drawImage时图片已经加载完成,这也是Canvas类应用/游戏的通用资源处理方案。
代码实现
基础回调写法
// 创建单张图片,直接返回实例 const createImage = function(src) { const image = new Image(); image.src = src; image.onerror = () => console.error(`图片加载失败:${src}`); return image; } // 批量预加载所有图片 function preloadImages(srcList, callback) { const imageMap = {}; let loadedCount = 0; const total = srcList.length; srcList.forEach(src => { const img = createImage(src); imageMap[src] = img; img.onload = () => { loadedCount++; if (loadedCount === total) { callback(imageMap); // 全部加载完成后触发回调 } } }) } // 用法示例 const allImageSrc = [ "images/map.png", // 把你需要的数百张图片路径全部放在这个数组里 ] preloadImages(allImageSrc, (imageMap) => { // 所有绘制逻辑都放在这个回调里,直接用图片对象即可 const map = imageMap["images/map.png"]; ctx.drawImage(map, 0, 0, 224, 292); // 其他绘制代码不需要再写onload逻辑 })
更简洁的async/await写法
// 用Promise封装单张图片加载 function createImage(src) { return new Promise((resolve, reject) => { const img = new Image(); img.src = src; img.onload = () => resolve(img); img.onerror = () => reject(new Error(`图片加载失败: ${src}`)); }) } // 批量预加载 async function preloadImages(srcList) { const imgPromises = srcList.map(src => createImage(src)); const imgList = await Promise.all(imgPromises); // 转为路径为key的映射,方便调用 return srcList.reduce((map, src, index) => { map[src] = imgList[index]; return map; }, {}) } // 用法示例 async function initCanvas() { const imageMap = await preloadImages([ "images/map.png", // 其他图片路径 ]); // 后续所有绘制逻辑直接使用imageMap里的对象即可 ctx.drawImage(imageMap["images/map.png"], 0, 0, 224, 292); } initCanvas();
内容的提问来源于stack exchange,提问作者Jacob Malland
相关产品推荐
相关产品推荐

