`loadLanguage` 中的竞争条件导致未处理的崩溃 `TypeError: 无法读取 undefined 的属性 (读取 'resolve')`
作者: codeCraft-Ritik创建于 2026年9月13日更新于 2026年9月13日
Step 1: Concurrency in loadLanguage
In src/worker-script/index.js:
const loadAndGunzipFile = async (_lang) => {
...
if (TessModule) {
if (dataPath) {
try {
TessModule.FS.mkdir(dataPath);
} catch (err) {
if (res) res.reject(err.toString()); // <--- Flaw 1: Dispatches 'reject' but continues execution!
}
}
TessModule.FS.writeFile(`${dataPath || '.'}/${lang}.traineddata`, data);
}
...
};
try {
await Promise.all(langsArr.map(loadAndGunzipFile));
if (res) res.resolve(langs); // <--- Flaw 2: Dispatches 'resolve' for the exact same jobId!
} catch (err) {
if (res) res.reject(err.toString());
}
Promise.all(langsArr.map(loadAndGunzipFile))runs file loading for all languages in parallel.- For the second language,
TessModule.FS.mkdir(dataPath)throwsErrnoError: FS error: File exists (EEXIST). - In
catch (err),res.reject(...)sends{ status: 'reject', jobId, action: 'loadLanguage' }to the host. - Crucially, it does not return or rethrow. Execution continues to
FS.writeFile, and whenPromise.allcompletes, line 196 callsres.resolve(langs)! - The worker has now dispatched both
rejectandresolvepackets for the exact samejobId.
Step 2: Crash on Host
- The host receives
{ status: 'reject' }first:promises[promiseId].reject(data); delete promises[promiseId]; // <--- promiseId is deleted! - The host receives the duplicate
{ status: 'resolve' }message immediately after:promises[promiseId].resolve({ jobId, data }); // <--- promises[promiseId] is undefined! - This throws `TypeError: Cannot read …
内容来源: naptha/tesseract.js