Я хочу создать файл инициализации для простой браузерной игры. Я использую 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?