我写的原代码如下:
const getBatchFileUrlAddLock = (minioObjectName) => {
if (sessionStorage.isGetResUrlReqLocked == 1) {
setTimeout(() => {
getBatchFileUrlAddLock(minioObjectName);
}, 600);
} else {
getBatchFileUrl(minioObjectName);
}
};
const getBatchFileUrl = (minioObjectName) => {
sessionStorage.isGetResUrlReqLocked = 1;
const params = {
env: "internet",
fileName: minioObjectName,
};
return new Promise((resolve, reject) => {
ActivitiApi.getBatchFileUrl(params)
.then((res) => {
const data = res.data;
if (data.code === 200) {
resolve(data.data);
} else {
throw new Error(data.message);
}
})
.catch((err) => {
if (err.message) {
Toast.fail(err.message);
} else {
Toast.fail("加载失败");
}
reject();
})
.finally(() => {
sessionStorage.isGetResUrlReqLocked = 0;
});
});
};
onMounted(async () => {
console.log(item.blockDataObj, "item.blockDataObj");
const { minioObjectName, urls } = item.blockDataObj ?? {};
// 由于图片URL会过期,因此将minioObjectName转换成最新的图片URL
// 单图片
if (minioObjectName) {
item.blockDataObj.url = await getBatchFileUrlAddLock(minioObjectName);
}
// 多图片
if (urls) {
urls.entries().map(async ([idx, url])=>{
// 若不为默认图片
if (!url.startsWith("http")) {
url = await getBatchFileUrlAddLock(url);
}
})
}
});
这段代码的目的是从 MinIO 对象存储获取文件 URL,并且实现了请求锁机制防止重复请求。不过存在几个问题需要修复:
1. getBatchFileUrlAddLock 函数没有正确返回 Promise
2. 递归调用 setTimeout 可能导致堆栈溢出
3. 多图片处理中使用 map 和 async/await 的方式不正确
4. 缺少类型检查和错误处理
下面是修复后的完整代码:
// 带锁机制的获取文件URL函数
const getBatchFileUrlAddLock = (minioObjectName) => {
return new Promise((resolve) => {
const checkLock = () => {
if (sessionStorage.isGetResUrlReqLocked === '1') {
setTimeout(checkLock, 600);
} else {
resolve(getBatchFileUrl(minioObjectName));
}
};
checkLock();
});
};
// 获取文件URL的核心函数
const getBatchFileUrl = (minioObjectName) => {
// 设置请求锁
sessionStorage.isGetResUrlReqLocked = '1';
const params = {
env: "internet",
fileName: minioObjectName,
};
return new Promise((resolve, reject) => {
ActivitiApi.getBatchFileUrl(params)
.then((res) => {
const data = res.data;
if (data.code === 200) {
resolve(data.data);
} else {
throw new Error(data.message || "获取文件URL失败");
}
})
.catch((err) => {
console.error("获取文件URL出错:", err);
Toast.fail(err.message || "加载失败");
reject(err);
})
.finally(() => {
// 释放请求锁
sessionStorage.isGetResUrlReqLocked = '0';
});
});
};
onMounted(async () => {
console.log(item.blockDataObj, "item.blockDataObj");
const { minioObjectName, urls } = item.blockDataObj || {};
try {
// 处理单图片
if (minioObjectName) {
item.blockDataObj.url = await getBatchFileUrlAddLock(minioObjectName);
}
// 处理多图片
if (Array.isArray(urls)) {
// 使用 Promise.all 并行处理所有URL
const updatedUrls = await Promise.all(
urls.map(async (url) => {
// 只处理非HTTP开头的URL(即需要从MinIO获取的URL)
if (typeof url === 'string' && !url.startsWith("http")) {
return await getBatchFileUrlAddLock(url);
}
return url;
})
);
// 更新URL数组
urls.splice(0, urls.length, ...updatedUrls);
}
} catch (error) {
console.error("处理图片URL时出错:", error);
// 可以添加全局错误提示
}
});
-
修复 Promise 返回问题:
getBatchFileUrlAddLock 现在正确返回 Promise
- 使用非递归的 setTimeout 实现锁检查
-
优化多图片处理:
- 使用
Promise.all 并行处理多个 URL 请求
- 使用
Array.isArray 进行类型检查
- 使用
splice 方法更新原数组,array.splice(start, deleteCount, item1, item2, ...)
-
增强错误处理:
- 添加 try/catch 块捕获异步错误
- 在 Promise 链中传递错误对象
- 添加更详细的错误日志
-
其他改进:
- 使用
|| {} 替代 ?? {} 以兼容更多浏览器
- 将锁状态存储为字符串而不是数字
- 添加类型检查确保处理的是字符串类型的 URL
这些修改使代码更加健壮,避免了潜在的错误,并且提高了性能和可维护性。