SQLite 从插件中的 SQLITE 数据库中读取

SQLite read from SQLITE database in plugin

我需要从我的插件中的 SQLite 数据库中读取值。为此,我找到了 sqlite.jsm 模块。我的问题是我想将一行作为全局变量,但是 SQLite(承诺和任务)中使用的代码是异步的。有什么方法可以将我的数据库中的信息收集到全局变量中吗?

let iDs = [];

Task.spawn(function* () {
    let db = yield Sqlite.openConnection({ path:
                                          permissionFilePath});

    try {
        let row = yield db.execute(
            "SELECT id FROM 'moz_hosts'");

        for ( i=0; i < row.length; i++) {
            console.log("row["+ i +"] :" +
                        row[i].getResultByIndex(0));
            yield iDs.push(row[i].getResultByIndex(0));
        }
    }
    finally {
        yield db.close();
    }
});

// Part of the code that doesn't work, because IDs are not yet assigned any values!
console.log("debug");
for (i=0; i<iDs.length; i++) {
  yield console.log("iDs ["+i+"] = "+ iDs[i]);
}

首先,对于一个 Task,你只需要产生 return 承诺的东西,因此 运行 是异步的。不需要yield iDs.push(row[i].getResultByIndex(0));,因为push操作会同步return数组的新长度。不过,这对于代码本身来说应该不是什么大问题。

你真的需要 id 是全局的吗?也许你可以重构你的代码,这样你就不需要全局保存它们了。

如果这不是一个选项,您将必须阻止所有将要访问 ID 的操作,直到 SQL 调用完成。您可以依靠 Task.spawn() 本身也会 return 一个承诺这一事实来做到这一点。这也有很好的副作用,你不需要额外的全局数组:

let idsPromise = Task.spawn(function*() {
    let ids = [];
    let db = yield Sqlite.openConnection({ path: permissionFilePath});

    try {
        let row = yield db.execute("SELECT id FROM 'moz_hosts'");
        for (let i = 0, len = row.length; i < len; i++) {
            ids.push(row[i].getResultByIndex(0));
        }
        // Instead of the loop you can also use:
        // ids = row.map(row => row.getResultByIndex(0));
    } finally {
        yield db.close();
    }

    return ids;
});

然后,在代码的其他部分,当您需要 id 时,您可以使用:

idsPromise.then(function(ids) {
    // Do something with ids
});

或者,您也可以在任务中获取它们:

Task.spawn(function*() {
    let ids = yield idsPromise;
});

您可以多次执行此操作。一旦承诺得到解决,then() 部分将尽快执行。