Понимание синхронного кода с помощью node.js async / await с пулом mysql - PullRequest
0 голосов
/ 28 октября 2019

Я хочу создать файл инициализации для простой браузерной игры. Я использую Node.js v8.10.0 и MySQL Ver 14.14 Distrib 5.7.27. На самом деле то, что я хочу сделать, было бы очень просто с синхронным языком, таким как Java, но я бы хотел сделать все в Node.js. Я пытался понять обещания и async / await в течение нескольких дней, но у меня неожиданные результаты, которые я не могу найти объяснения. Важная точность: я хочу, чтобы программа завершила сама, когда все будет сделано.

Проблема уже хорошо освещена во всем Интернете. Я даже использую промежуточное программное обеспечение, найденное в StackOverflow, для использования соединений пула с «обещанной» версией пакета mysql: классное промежуточное ПО для соединений пула с mysql оригинальный вопрос . Я изучил множество страниц документации по этому вопросу и подумал, что понял: (официальный документ Node.js по обещаниям и асинхронный / ожидающий) [https://nodejs.dev/modern-asynchronous-javascript-with-async-and-await], MDN документ по обещаниям , другоеХорошее объяснение по async / await . Однако я до сих пор не понимаю мою проблему.

Напомним, что здесь есть промежуточное программное обеспечение для mysql, которое я использую с node.js (написано Матиасом Хагеманом). Он отлично работает:

MySQL с использованием пула и обещаний

const util = require('util');
var mysql = require('mysql');
var pool = mysql.createPool({
    connectionLimit: 10,  // nb of simultaneous active connections
    host: "localhost",
    user: "root",
    password: "",
    database: "aelkyr_db"
});

// Ping database to check for common exception errors.
pool.getConnection((err, connection) => {
  if (err) {
    if (err.code === 'PROTOCOL_CONNECTION_LOST') {
      console.error('Database connection was closed.')
    };
    if (err.code === 'ER_CON_COUNT_ERROR') {
      console.error('Database has too many connections.')
    };
    if (err.code === 'ECONNREFUSED') {
      console.error('Database connection was refused.')
    };
  };

  if (connection) connection.release()

  return
});

// Promisify for Node.js async/await.
pool.query = util.promisify(pool.query);

module.exports = pool;

Простой оригинальный код

Тогда мой код. В начале есть только простой код для заполнения таблицы MySQL множеством строк. Примечание. Таблица ранее создавалась вручную в терминале:

var pool = require('./db_pool_connections.js');
const sizeSquareMap = 31;
const gameboardTableName = "gameboard_test_2";
for (let r = 0; r < sizeSquareMap; r++) {
        for (let c = 0; c < sizeSquareMap; c++) {
            sql = `insert into ${gameboardTableName}
(r, c) values (${r}, ${c});`;
            pool.query(sql, function (err, result) {
                if (err) {
                    throw err
                };
            });
        };
    };
    console.log("ok 2");
};

Добавление нескольких запросов с пулом без обещаний

Реальные проблемы начинаются, когда я понял, что хочу создать полную таблицу изфайл node.js напрямую. Следовательно, я написал это:

var pool = require('./db_pool_connections.js');
const sizeSquareMap = 31;
const generateMap = true; 
if (generateMap) {
    // generate the new table 
    const gameboardTableName = "gameboard_test_2";
    pool.query(`create table aelkyr_db.${gameboardTableName} ( 
        gameboxId int(11) not null primary key auto_increment,
        r int not null default 0,
        c int not null default 0,
        biome varchar(200) default '',
        players varchar(2000) default '',
        objects varchar(6000) default ''
    );`, function (err, result) {
        if (err) {
            throw err;
        }
        ;
    });

    // populate the table with empty gameboxes
    let sql;
    for (let r = 0; r < sizeSquareMap; r++) {
        for (let c = 0; c < sizeSquareMap; c++) {
            sql = `insert into ${gameboardTableName} (r, c) values (${r}, ${c});`;
            pool.query(sql, function (err, result) {
                if (err) {
                    throw err
                };
                // console.log(result);
            });
        };
    };
    //process.exit(1); //error : Error: Pool is closed.
    //pool.end();
};

Этот код работает, но не заканчивается, насколько я понимаю, из-за соединения с пулом, которое никогда не закрывается . Поэтому я попытался использовать pool.end ();или process.exit (1);чтобы закрыть программу по окончании выполнения;но я получаю ту же ошибку: ошибка: ошибка: пул закрыт.

Попытка использовать обещания с async / await

Похоже, что закрывающий код pool.end ();выполняется перед циклом for, потому что Node.js (JavaScript) по своей природе асинхронный. Чтобы столкнуться с проблемой, я погрузился в обещания и синхронизирую / жду с надеждой, что смогу преобразовать свой код во что-то, что ведет себя как синхронный код. Я пробовал 2 версии кода: ВЕРСИЯ 1 (не работает)

//V1: I want to use await with all the async functions to make the code synchronous.
var pool = require('./db_pool_connections.js');

// set up the generation code
const generateMap = true;  // [OK] properly working
const generateRuins = false;    //

// [generateMap]
async function populateGameboard(sizeSquareMap, gameboardTableName) {
    for (let r = 0; r < sizeSquareMap; r++) {
        for (let c = 0; c < sizeSquareMap; c++) {
            sql = `insert into ${gameboardTableName} (r, c) values (${r}, ${c});`;
            pool.query(sql, function (err, result) {
                if (err) {
                    throw err
                };
            });
        };
    };
    console.log("ok 2");
};

const generateNewMap = async function (gameboardTableName, sizeSquareMap) {
    const qry = await pool.query(`create table aelkyr_db.${gameboardTableName} ( 
        gameboxId int(11) not null primary key auto_increment,
        r int not null default 0,
        c int not null default 0,
        biome varchar(200) default '',
        players varchar(2000) default '',
        objects varchar(6000) default ''
    );`, function (err, result) {
        if (err) {
            throw err;
        }
        ;
    });
    console.log("ok 1", qry);
    await populateGameboard(sizeSquareMap, gameboardTableName);
    console.log("ok 3");
};

generateNewMap("gameboard_test_2", 31 )
    .then(console.log("ok 4"))
    .catch(error =>{
        console.log(error)
    });

И ВЕРСИЯ 2 (работает, но никогда не заканчивается.)

//V2: Only a small difference, I remove the 2 "await"
var pool = require('./db_pool_connections.js');

// set up the generation code
const generateMap = true;

// [generateMap] 
async function populateGameboard(sizeSquareMap, gameboardTableName) {
    for (let r = 0; r < sizeSquareMap; r++) {
        for (let c = 0; c < sizeSquareMap; c++) {
            sql = `insert into ${gameboardTableName} (r, c) values (${r}, ${c});`;
            pool.query(sql, function (err, result) {
                if (err) {
                    throw err
                };
            });
        };
    };
    console.log("ok 2");
};

const generateNewMap = async function (gameboardTableName, sizeSquareMap) {
    const qry = pool.query(`create table aelkyr_db.${gameboardTableName} ( 
        gameboxId int(11) not null primary key auto_increment,
        r int not null default 0,
        c int not null default 0,
        biome varchar(200) default '',
        players varchar(2000) default '',
        objects varchar(6000) default ''
    );`, function (err, result) {
        if (err) {
            throw err;
        }
        ;
    });
    console.log("ok 1", qry);
    populateGameboard(sizeSquareMap, gameboardTableName);
    console.log("ok 3");
};

generateNewMap("gameboard_test_2", 31 )
    .then(console.log("ok 4"))
    .catch(error =>{
        console.log(error)
    });

Вывод VERSION 1 в моем терминале:

ʘ node db_gameboard_init.js
ok 4
^C

Обратите внимание, я вижу, что код .then () выполняется непосредственно при вызове функции generateNewMap (). И вывод версии 2 в моем терминале:

ʘ node db_gameboard_init.js
ok 1 Promise { <pending> }
ok 2
ok 3
ok 4
^C

Следовательно, мне бы очень хотелось получить ответы на следующие вопросы:

1) V2, кажется, дает хорошийрезультат, но добавление ".then (pool.end ())" после ".then (console.log (" ok 4 "))" выдает ошибку:

ʘ node db_gameboard_init.js
ok 1 Promise { <pending> }
ok 2
ok 3
ok 4
/*****/db_gameboard_init.js:39
            throw err;
            ^

Error: Pool is closed.

Почему? Если весь код уже запущен, почему такая ошибка? Нет необходимости в другом подключении? 2) Почему .then () с generateNewMap () вызывается первым, что делает код бесконечным? 3) Как правильно завершить выполнение программы синхронно. 4) Что означает «Обещание {}», учитывая результаты программы V2?

...