我寫的原代碼如下:
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
這些修改使代碼更加健壯,避免了潛在的錯誤,并且提高了性能和可維護性。