возвращаемое значение из mariadb в функции nodejs

#node.js #asynchronous #mariadb

#node.js #асинхронный #mariadb

Вопрос:

Это мой код:

 const mariadb = require('mariadb');
var test = async function(){
  var ret = "";
  await mariadb.createConnection({
        host: "localhost",
        user: "dave",
        connectionLimit: 5,
        password: "!@#",
        database: "db",
        rowsAsArray: false
  }).then((data)=>{
    ret = "test";
  });
  return ret;
}

console.log(test());
  

Как я могу получить возврат из then с помощью await?

Я знаю, что подобные вопросы поднимались во многих случаях, но я не смог найти ни одного с помощью mariadb.

Ответ №1:

Я уже вижу несколько подводных камней, с которыми вы, как новички, столкнетесь в этом коде:

  • avait ожидает возврата результатов, так как он получит Promisses для ее решения
  • then решает обещания асинхронно
  • функция, определенная как async всегда возвращает обещания

После минутного восторга ‘async / await’ теперь я стараюсь избегать его. Главным образом потому, что каждая функция, в которой я использую асинхронную функцию, также должна быть асинхронной, пока вы не используете then , например, сделайте небольшой тест:

   let test = async function() {
    let x = await 11
    return 1;
  }
  console.log(test()) //returns: Promise { <pending> }
  

Там нет ничего асинхронного, но добавление async / await вызвало беспорядок.

Теперь исправлены ошибки в вашем коде

 const mariadb = require('mariadb');
// use local scope `let` instead global `var`
let test = async function(){
  let conn = await mariadb.createConnection({
        host: "localhost",
        user: "dave",
        connectionLimit: 5,
        password: "!@#",
        database: "db",
        rowsAsArray: false
  });
  return conn.query("SELECT 1 as val") // no sense using `avait` because `test()` returns `promise`
}

test().then(function(rows) { console.log(rows)});
  

и без asnc. then может возвращать обещание, и это может быть разрешено следующим then

 
mariadb.createConnection(...).then(conn => { // create connection
    return conn.query("SELECT 1 as val") // make query
}).then(rows => { //get result
    console.log(rows)
}).catch(err => console.error(err)) // get errors

  

Кстати: заинтересовался построителем запросов, например knex.js . Это позволяет писать код, независимый от database engine.

Обновить

Начнем с того, что Node основан на событиях.

Давайте рассмотрим пример получения данных из базы данных. В PHP / C вы делаете запрос, ждете, получаете результат. И это поведение имитируется с помощью await . (Ожидание появилось где-то около версии 8)

Обычно код в Node работает так, что вы выполняете запрос, и Node создает новый поток. Старая команда запустите next, в новой вы получите результаты. (ОК, я вру, но это проще объяснить).

Итак, вы должны обработать событие получения данных. И, более конкретно, promise предоставления данных. С помощью await , .then () или callback (hell)

первое объяснение кода:

Вы пытаетесь вернуть ret , но этот код сначала выполняется return ret , а после выполняется присваивание.

await «возвращает» данные, поэтому вам следует использовать let var_name = await asyncFunction()

Я предполагаю, что вы хотите этого:

 let getSomeDataFromDB = function(){
  return mariadb.createConnection([skip]).then(conn => {
    return conn.query("SELECT 1 as val") 
  })
}
let rows = await getSomeDataFromDB()
  

В этой функции вы возвращаете promise, которые возвращают promise. И await эта цепочка обещаний разрешена.

Но вот «небольшая» ошибка в коде. Потому что вы подключаетесь и нигде не прерываете свое соединение. Поэтому лучше иметь глобальный объект connection или использовать что-то вроде этого:

 
let getSomeDataFromDB = function(){
  return new Promise(function(resolve, reject){
    mariadb.createConnection([skip]).then(conn => {
      conn.query("SELECT 1 as val")
        .then(rows=>resolve(rows))
        .catch(e=>reject(e))
        .then(()=>conn.close())
    }).catch(e => reject(e))
  })
}
let rows = await getSomeDataFromDB()
  

И здесь вы обнаруживаете еще одну важную вещь: resolve не прерывает выполнение кода. Несмотря на то, что данные возвращаются пользователю, вы все еще можете что-то сделать.

Или то же самое с await

 let getSomeDataFromDB = async function(){
  let conn = await reateConnection([skip])
  let rows = await conn.query("SELECT 1 as val")
  await conn.close();
  return rows;
}
let rows = await getSomeDataFromDB()
  

Комментарии:

1. К сожалению, ни одно из вышеперечисленных решений не исправит мой код, потому что у меня довольно вложенные функции. Я попытаюсь перестроить весь код основного движка приложения, но большое вам спасибо за объяснение. Теперь я более или менее знаю, как его перехватить. Если кто-нибудь знает какое-либо необычное решение из приведенной выше ситуации, я буду благодарен.

2. @Dave Знаешь, ты задал общий вопрос, значит, у тебя есть общий ответ. Было бы неплохо знать, например: какую версию узла вы должны использовать. Я надеюсь, что обновленный ответ немного прояснил ситуацию. Если нет, вставьте фрагмент кода, который вы не понимаете. Если вы свяжетесь со мной, я попытаюсь объяснить, что там происходит.