Optimize LuckyExcel xlsx preview conversion with Web Worker (#766)

* Optimize LuckyExcel conversion with worker

* Fallback LuckyExcel worker errors to main thread
This commit is contained in:
Spencer.Chang
2026-06-29 11:20:50 +08:00
committed by GitHub
parent 3e16ed9d3b
commit 67c6ba3b13
3 changed files with 168 additions and 59 deletions

View File

@@ -0,0 +1,54 @@
// LuckyExcel's bundled getBinaryContent reads window.XMLHttpRequest.
// Web Worker exposes XMLHttpRequest on self, so provide a minimal window alias
// before loading the UMD bundle.
self.window = self;
importScripts('./luckyexcel.umd.js');
self.console.log = function () {};
self.onmessage = function (event) {
var data = event.data || {};
var url = data.url;
var name = data.name;
if (!url) {
self.postMessage({
type: 'error',
message: '文件URL为空'
});
return;
}
try {
LuckyExcel.transformExcelToLuckyByUrl(
url,
name,
function (exportJson, luckysheetfile) {
if (!exportJson || !exportJson.sheets || exportJson.sheets.length === 0) {
self.postMessage({
type: 'error',
message: '读取excel文件内容失败!'
});
return;
}
self.postMessage({
type: 'success',
exportJson: exportJson
});
},
function (error) {
self.postMessage({
type: 'error',
message: error && error.message ? error.message : String(error)
});
}
);
} catch (error) {
self.postMessage({
type: 'error',
message: error && error.message ? error.message : String(error)
});
}
};

View File

@@ -3938,7 +3938,7 @@ var LuckySheet = /** @class */function (_super) {
_this.sheetList = allFileOption.sheetList; _this.sheetList = allFileOption.sheetList;
_this.imageList = allFileOption.imageList; _this.imageList = allFileOption.imageList;
_this.hide = allFileOption.hide; _this.hide = allFileOption.hide;
console.log(allFileOption, 'allFileOption'); // console.log(allFileOption, 'allFileOption');
_this.dataVerificationSelectCount = allFileOption.dataVerificationSelectCount; _this.dataVerificationSelectCount = allFileOption.dataVerificationSelectCount;
//Output //Output
_this.name = sheetName; _this.name = sheetName;

View File

@@ -225,8 +225,11 @@
// 使用异步方式加载 // 使用异步方式加载
await new Promise(resolve => setTimeout(resolve, 100)); // 给UI更新一点时间 await new Promise(resolve => setTimeout(resolve, 100)); // 给UI更新一点时间
// 或者使用现有的同步方法但放在setTimeout中避免阻塞 const exportJson = await transformWithWorker(value, name);
await transformWithTimeout(value, name);
updateProgress(80);
await createLuckysheet(exportJson);
updateProgress(100); updateProgress(100);
@@ -243,23 +246,81 @@
} }
} }
// 使用setTimeout将同步任务拆分 function transformWithWorker(value, name) {
function transformWithTimeout(value, name) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
updateProgress(50); updateProgress(50);
// 将转换过程放在setTimeout中避免阻塞主线程 if (!window.Worker) {
setTimeout(() => { transformOnMainThread(value, name, resolve, reject);
return;
}
let worker;
try { try {
LuckyExcel.transformExcelToLuckyByUrl(value, name, function(exportJson, luckysheetfile){ worker = new Worker('xlsx/luckyexcel-worker.js');
if(exportJson.sheets==null || exportJson.sheets.length==0){ } catch (error) {
transformOnMainThread(value, name, resolve, reject);
return;
}
let settled = false;
const fallbackToMainThread = function(error) {
if (settled) {
return;
}
settled = true;
worker.terminate();
if (error) {
console.warn('Excel Worker转换失败回退主线程转换:', error);
}
transformOnMainThread(value, name, resolve, reject);
};
worker.onmessage = function(event) {
const data = event.data || {};
if (data.type === 'success') {
settled = true;
worker.terminate();
resolve(data.exportJson);
return;
}
if (data.type === 'error') {
fallbackToMainThread(data.message || 'Excel转换失败');
}
};
worker.onerror = function(error) {
fallbackToMainThread(error && error.message ? error.message : error);
};
worker.postMessage({
url: value,
name: name
});
});
}
function transformOnMainThread(value, name, resolve, reject) {
try {
LuckyExcel.transformExcelToLuckyByUrl(value, name, function(exportJson, luckysheetfile) {
if (!exportJson || !exportJson.sheets || exportJson.sheets.length === 0) {
reject(new Error("读取excel文件内容失败!")); reject(new Error("读取excel文件内容失败!"));
return; return;
} }
updateProgress(80); resolve(exportJson);
}, function(error) {
reject(error);
});
} catch (error) {
reject(error);
}
}
// 使用requestAnimationFrame来更新UI避免阻塞 function createLuckysheet(exportJson) {
return new Promise((resolve, reject) => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
try { try {
window.luckysheet.destroy(); window.luckysheet.destroy();
@@ -305,12 +366,6 @@
} }
}); });
}); });
} catch (error) {
reject(error);
}
}, 100);
});
} }
// 页面加载完成后开始异步加载 // 页面加载完成后开始异步加载