首页 > 解决方案 > 如何强制异步调用函数的顺序执行

问题描述

我对异步代码的想法很陌生,并且仍在努力思考一切是如何工作的。

我正在构建一个将与数据库交互的 Node Express 应用程序。在开发环境中运行时,我希望它与 Sqlite 数据库交互。(生产数据库不会使用Sqlite,这只适用于创建小型开发环境。)

我的问题是我无法控制对数据库的查询的执行顺序和时间。

我想构建我的 SqliteDatabase.js 文件,使其只能按顺序执行查询,尽管该文件中的函数将被异步运行的程序的其他部分调用。

我怎样才能做到这一点?

作为参考,这是我目前设置 SqliteDatabase.js 文件的方式:

var debug = require('debug')('app:DATABASE');
var sqlite = require('sqlite3').verbose();

open = function() {
    var db = new sqlite.Database('./test-database.db', sqlite.OPEN_READWRITE | sqlite.OPEN_CREATE, function(err) {
        if (err) {
            debug("We've encountered an error opening the sqlite database.");
            debug(err);
        } else {
            debug("Sqlite database opened successfully.");
        }
    });
    return db;
}

executeSQLUpdate = function(sql, next) {
    var db = open();
    db.serialize(function() {
        console.log("executing " + sql);
        db.run(sql);
        db.close();
        next();
    });
}

exports.executeSQLUpdate = executeSQLUpdate;

有没有办法建立一个队列,当调用“executeSQLUpdate”函数时,请求被添加到队列中,直到所有先前的请求都完成后才开始?

举个例子,看看这段代码,它利用了我的 SqliteDatabase.js 文件:

ar database = require('../../bin/data_access/SqliteDatabase.js');

var createTestTableStmt = "CREATE TABLE IF NOT EXISTS Test(\n" +
    "Name TEXT PRIMARY KEY NOT NULL UNIQUE,\n" +
    "Age INT NOT NULL,\n" +
    "Gender TEXT NOT NULL\n" +
    ");";

var clearTestTableStmt = "DELETE FROM Test;";

var testInsertStmt = "INSERT INTO Test (Name, Age, Gender)\n" +
    "VALUES (\"Connor\", 23, \"Male\");";

createTable = function() {
    database.executeSQLUpdate(createTestTableStmt, clearTable);
}

clearTable = function() {
    database.executeSQLUpdate(clearTestTableStmt, insertRow);
}

insertRow = function() {
    database.executeSQLUpdate(testInsertStmt, function() {
        console.log("Done!");
    });
}

createTable();

上述代码 10 次中有 9 次运行良好,但每隔一段时间,在调用“clearTable”函数之前调用“insert row”函数,由于违反数据库约束而引发错误。

如何更改 SqliteDatabase.js 文件的实现以避免此问题?

标签: javascriptnode.jssqliteexpress

解决方案


You can use async to do this using await. This code will wait for each asynchronous database call to complete before executing the next line.

async function createTable() {

  await database.executeSQLUpdate(createTestTableStmt);
  await database.executeSQLUpdate(clearTestTableStmt);
  await database.executeSQLUpdate(testInsertStmt);

  console.log("Done!");

}

Your console.log statement will only execute once all three have completed.

I should also mention that you need a try...catch block around the three database calls to trap any errors and provide an alternate exit point if something should go wrong.


推荐阅读