У меня есть сокет, который прослушивает события (строки) через UDP. Каждый раз, когда он получает строку, генерируется запрос SQL. Моя проблема заключается в том, чтобы он работал асинхронно, чтобы запросы стояли в очереди и не пытались получить доступ к базе данных, пока выполняется другой запрос.
Псевдо:
socket.on('message', function (msg) {
switch (msg) {
case "case1":
storeRows();
break;
//there's a new message every 1-2 secs
...
}
var rows = []; //push results of all queries here
function storeRows() {
rows.push(getFromDB());
}
function getFromDB() {
var sqlString = "SELECT * ..."
var req = new Req(sqlString, function(err, rowCount) {
...
}
var resultsArray = [];
req.on('row', function (cols) {
//add results to resultsArray
}
return resultsArray;
}
В основном мне нужно, чтобы getFromDB () выполнялся асинхронно, дождитесь завершения предыдущего запроса, прежде чем запускать следующий. Я не знаю, как это сделать. Я использую tedious.js для доступа к базе данных SQL Server.
Редактировать:
var config = {
userName: "admin",
password: "pw",
server: "test",
domain: "test",
options: {
port: '10322'
}
}
connection = new Connection(config);
connection.on('connect') {
isConnected = true;
}
getCoordinates(vehicleID, fromTime, toTime) {
var SQLString = "Select * FROM coordinates WHERE TimeStamp BETWEEN '" + fromTime + "' AND '" + toTime + "' AND vehicleID = " + vehicleID;
var rowsToSend = [];
var req = new Req(SQLString, function(err, rowCount) {
if (err) console.info(err)
else console.info(rowCount);
}
req.on('row', function (columns) {
var rowArray = [];
columns.forEach(function (column) {
var colValue = column.value;
switch (column.metadata.colName) {
case "ID":
if (rowArray.length > 0)
rowsToSend.push(rowArray);
rowArray = new Array();
break;
default:
rowArray.push(colValue);
break;
}
});
rowsToSend.push(rowArray);
});
connection.execSql(req);
req.on('doneProc', function () {
return(rowsToSend);
}
}
//called every few seconds
function runQueries() {
someArray.push(getCoordinates ());
}
При отправке запроса во время выполнения другого он возвращает Requests can only be made in the LoggedIn state, not the SentClientRequest state.
Мы не сможем помочь вам, не увидев больше вашего кода. Но похоже, что проблема не в синхронном и асинхронном, а в каком-то другом виде управления состоянием. Обновите свой вопрос, добавив минимальный воспроизводимый пример, демонстрирующий проблему с простыми запросами (многие из нас имеют доступ к SQL Server и могут быстро настроить локальный пример, чтобы помочь вам).
@ T.J.Crowder Какое отношение это имеет к управлению государством? Вопрос кажется довольно простым. У меня есть сообщение, которое должно запрашивать базу данных каждые 1-2 секунды, и я хочу убедиться, что запросы не выполняются параллельно. Ниже я привел пример.
Обратный вызов, который вы передаете вызову new Req(), должен отвечать на текущее сообщение данными или ошибкой. Затем, если в вашей очереди запросов все еще есть запросы, сделайте то же самое. Таким образом, все запросы, поступающие через сокет, могут оставаться синхронными. Только запрос к базе данных, запускающий сокет для отправки ответа, является асинхронным, поскольку вы хотите дождаться завершения предыдущего запроса, а не выполнять все запросы параллельно. Сохранение ожидающих запросов может быть таким же простым, как нажатие и извлечение массива.
@FrankerZ - Я не понимаю, как это не может быть связано с управлением состоянием, поскольку OP явно пытается выполнить запрос, когда он не находится в «состоянии LoggedIn». Ответ ниже в лучшем случае является дико спекулятивным.
Добавлен пример кода.
@ user2979612 - Добавленный код содержит основные синтаксические ошибки. Опять же, опубликуйте MCVE.
Полный код находится в частной сети, и я не могу легко передать его в Интернет. Это лучшее, что я могу сделать. Но ответ @ FrankerZ - это более или менее то, что я искал.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете создать что-то вроде процессора, который создает очередь на основе массива и позволяет одновременно выполнять только один запрос к базе данных. Вот пример использования функций async / await с обещаниями:
class Processor {
constructor() {
this.queue = [];
this.queryRunning = false;
}
// Main query function.
// Add the query to a queue, and try to process the queue.
query(query) {
return new Promise((resolver) => {
this.queue.push({
query,
resolver
});
this.tryProcessNext();
});
}
// Try to process the next element of the queue
tryProcessNext() {
let self = this;
// If it's running, or queue is empty, simply do nothing
if (this.queue.length === 0 || this.queryRunning)
return;
this.queryRunning = true;
// Get the first added element to the queue (And shorten the array at the same time)
let qry = this.queue.shift();
// Run query, and use `qry.resolver()` to resolve the original promise.
setTimeout(function() {
qry.resolver(`Result: ${qry.query}`);
self.queryRunning = false;
// If there's anything next in the queue, try to process that next
self.tryProcessNext();
}, 1500);
}
}
const proccessor = new Processor();
let i = 0;
// A simple function to demonstrate adding queries via a websocket.
setInterval(async function() {
console.info(`Adding query: QUERY ${++i}`);
var res = await proccessor.query(`QUERY ${i}`);
console.info(res);
}, 1000);
Из их документация ясно, что запросы к базе данных с использованием tedious.js уже являются асинхронными (как можно было бы надеяться, в среде Node.js). Используете ли вы какую-то опцию или что-то подобное, чтобы вместо этого они блокировались? Не могли бы вы показать нам реальное содержимое
getFromDB(с опущенным SQL это нормально)?