LokiSFSAdapter在Linux正常运行却在Windows异常的原因排查
从你的描述来看,这个问题并不是单纯的API误用,而是LokiJS文件系统适配器在Windows环境下的路径、权限,以及Electron生命周期配合上的适配问题——毕竟Linux和Windows的文件系统、进程退出机制差异不小。下面我结合类似的跨平台调试经验,给你几个针对性的解决方案:
一、先排查最常见的路径与权限问题
Windows对文件路径的处理(比如分隔符、默认目录的写入权限)和Linux差异很大,你当前用相对路径'database.json'初始化LokiJS,很可能导致Windows下数据库文件被存在了无权写入的目录,或者路径解析错误。
解决方法:使用Electron提供的标准用户数据目录
Electron的app.getPath('userData')会返回跨平台的、有写入权限的用户数据目录,把数据库文件放在这里就不会有问题:
// 渲染进程中(需确保nodeIntegration开启,或用preload脚本) const { app } = require('electron').remote; const path = require('path'); // 获取正确的跨平台数据存储路径 const dbPath = path.join(app.getPath('userData'), 'database.json'); // 然后用这个路径初始化LokiJS var db = new loki(dbPath, { autoupdate: true, autoload: true, autoloadCallback: setupHandler, adapter: sfsAdapter });
二、修复异步操作的等待问题
你的代码里调用db.saveDatabase()时没有加await,这是个大问题——LokiJS的saveDatabase是异步方法,Windows下文件IO速度比Linux慢,很可能还没完成保存,应用就已经退出了,导致数据丢失。
解决方法:所有saveDatabase调用都要等待完成
修改你的actions:
const actions = { async addProfile (context) { db.getCollection('profiles').insert({ /* default data */ }) await db.saveDatabase() // 必须加await,确保数据写入完成 context.commit('updateProfiles') }, async updateProfile (context, obj) { db.getCollection('profiles').update(obj) await db.saveDatabase() context.commit('updateProfiles') }, // 其他addAd/deleteAd等方法同理,都要await saveDatabase }
同时,setupHandler里的Vuex提交也要确保Vuex已经初始化完成,避免因时序问题导致数据未更新:
function setupHandler () { setupCollection('ads') setupCollection('profiles') // 用setTimeout或Vue.nextTick确保Vuex就绪 setTimeout(() => { MainState.commit('updateAds') MainState.commit('updateProfiles') }, 100); }
三、替换不可靠的window.onbeforeunload
Windows下Electron的window.onbeforeunload事件经常因为窗口关闭的优先级问题无法触发,导致你来不及保存数据库。
解决方法:在Electron主进程监听before-quit事件
主进程是整个应用的入口,before-quit事件会在应用退出前可靠触发,在这里处理数据库保存更稳妥:
// 主进程代码 const { app } = require('electron'); // 假设你把db实例通过IPC传递到主进程,或者直接在主进程初始化LokiJS app.on('before-quit', async () => { if (db) { await db.saveDatabase(); db.close(); } });
如果你的LokiJS是在渲染进程初始化的,可以通过IPC通知主进程执行保存:
// 渲染进程 const { ipcRenderer } = require('electron'); window.onbeforeunload = async () => { await ipcRenderer.invoke('save-database'); }; // 主进程 const { ipcMain } = require('electron'); ipcMain.handle('save-database', async () => { if (db) { await db.saveDatabase(); db.close(); } });
四、尝试替换LokiJS的适配器
有时候LokiJS的Structured File System Adapter在Windows下存在兼容性bug,你可以尝试换成普通的FileSystem Adapter测试:
// 替换导入的适配器 import LokiFSAdapter from 'lokijs/src/loki-fs-adapter'; var fsAdapter = new LokiFSAdapter(); // 初始化时使用新适配器 var db = new loki(dbPath, { autoupdate: true, autoload: true, autoloadCallback: setupHandler, adapter: fsAdapter });
总结
按照我的经验,你遇到的问题大概率是路径权限+异步未等待+退出事件不可靠三者共同导致的。先从路径和await saveDatabase这两点入手修改,应该能解决大部分问题;如果还不行,再替换适配器和退出事件的处理方式。
内容的提问来源于stack exchange,提问作者sjaustirni

