Node.js - используйте асинхронную функцию, чтобы получить возвращаемое значение синхронно без обратных вызовов - PullRequest
0 голосов
/ 03 марта 2019

У меня есть функция для получения списка идентификаторов пользователей из базы данных mysql.

function GetUsers(callback) {
  UpdateLogFile('Function Call: GetUsers()')
  var users = []
  Database.execute( connectionStr,
    database => database.query('select UserID from Users')
    .then( rows => {
      for (let i = 0; i < rows.length; i++){
        users.push(rows[i].UserID)
      }
      return callback(users)
    })
  ).catch( err => {
    console.log(err)
  })
}

Для справки:

Класс базы данных , полученный из здесь

const mysql = require( 'mysql' )
class Database {
  constructor( config ) {
    this.connection = mysql.createConnection( config )
  }
  query( sql, args ) {
    return new Promise( ( resolve, reject ) => {
      this.connection.query( sql, args, ( err, rows ) => {
        if ( err )
          return reject( err )
        resolve( rows )
      })
    })
  }
  close() {
    return new Promise( ( resolve, reject ) => {
      this.connection.end( err => {
        if ( err )
          return reject( err )
        resolve()
      })
    })
  }
}

Database.execute = function( config, callback ) {
  const database = new Database( config )
  return callback( database ).then(
    result => database.close().then( () => result ),
    err => database.close().then( () => { throw err } )
  )
}

После нескольких часов изучения обещаний и обратных вызовов я наконец смог заставить GetUsers() хотя бы поработать и вернуть то, что искал.Тем не менее, мне кажется, что я могу использовать его только так:

GetUsers(function(result){
    // Do something with result
})

Но мне бы очень хотелось, чтобы в функции был традиционный оператор return, чтобы я мог использовать его следующим образом: var users = GetUsers().Я видел посты, в которых говорилось, что это невозможно из-за природы асинхронных функций, но я все еще надеюсь, что мне действительно хотелось бы избежать возможности callback hell .Я попробовал приведенный ниже код, но «пользователи» только что получили результаты после выполнения.Итак, моя главная цель - получить возвращаемое значение из GetUsers() без объединения обратных вызовов, поскольку у меня есть другие функции, которые ведут себя аналогично.Это возможно?

var users
GetUsers(function(result){
    users = result
})
console.log(users)

Ответы [ 2 ]

0 голосов
/ 03 марта 2019

Это очень запутанная тема, и мне потребовалось некоторое время, чтобы действительно понять, почему то, что вы спрашиваете, просто невозможно (по крайней мере, точно так, как вы спрашиваете).Для примеров я буду использовать Python Django и Node.js для сравнения.

Sync

def synchronous():
    print('foo') //this will always print first
    print('bar')

def getUsers():

    with connection.cursor() as cursor:
        cursor.execute('SELECT * FROM USERS')  //this query is executed
        users = cursor.fetchall()

        print('foo') //this doesn't trigger until your server gets a response from the db, and users is defined
        print(users)

Async

function asynchronous() {
    console.log('foo'); //this will also always print first
    console.log('bar');
}

function getUsers() {
   var connection = mysql.createConnection(config);
   connection.query('SELECT * FROM USERS', function(error, users) { //this is a "callback"
     console.log(users); //this will print
     //everything inside of here will be postponed until your server gets a response from the db

   });
   console.log('foo') //this will print before the console.log above
   console.log(users); //this will print undefined
   //this is executed before the query results are in and will be undefined since the "users" object doesn't exist yet.
}

A callback isпросто функция, которую должен запускать ваш сервер, как только вы получите ответ.Обычно мы используем фактическое слово «обратный вызов», например:

function getUsers(callback) {
   var connection = mysql.createConnection(config);
   connection.query('SELECT * FROM USERS', function(error, users) { 
   if (error) throw error; //always do your error handling on the same page as your query.  Its much cleaner that way

   callback(users) //server asks what to do with the "users" object you requested
   });
}

Теперь где-нибудь еще на вашем сервере:

getUsers(function(users) {// the callback gets called here
  console.log(users); //do what you want with users here
});

Функция getUsers принимает некоторую другую функцию (т.е.callback) в качестве аргумента и выполняет эту функцию после выполнения запроса.Если вы хотите сделать то же самое, не используя слово «обратный вызов», вы можете использовать функцию await / async, такую ​​как fsociety, или вы явно пишете свой код, а не создаете функции, которые принимают другие функции в качестве аргументов.

Эта функциональность идентична приведенному выше коду:

var connection = mysql.createConnection(config);
connection.query('SELECT * FROM USERS', function(error, users) { 
if (error) throw error;
console.log(users); 
});

Ад обратного вызова неизбежен, но на самом деле это не так уж и плохо, как только вы его освоите.

0 голосов
/ 03 марта 2019

Вместо этого используйте функцию async-await.

async function GetUsers(callback) {
try {  
     UpdateLogFile('Function Call: GetUsers()')
     var users = []
     let rows = await Database.execute( connectionStr,
     database => database.query('select UserID from Users')

     for (let i = 0; i < rows.length; i++){
        users.push(rows[i].UserID)
      }
      return callback(users)

   } catch(err) {
    console.log(err)
  }
}

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...