【问题标题】:Node.js - Use asynchronous function to get a return value in a synchronous way without callbacksNode.js - 使用异步函数以同步方式获取返回值,无需回调
【发布时间】:2019-07-24 18:17:22
【问题描述】:

我有一个函数可以从 mysql 数据库中检索用户 ID 列表。

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)
  })
}

供参考:

数据库类来自here

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)

【问题讨论】:

标签: mysql node.js asynchronous callback


【解决方案1】:

改用 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)
  }
}

希望这会有所帮助!

【讨论】:

【解决方案2】:

这是一个非常令人困惑的话题,我花了一段时间才真正理解为什么你所问的根本不可能(至少,以你所问的确切方式)。对于示例,我将使用 python Django 和 Node.js 进行比较。

同步

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)

异步

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.
}

回调 只是你的服务器在收到响应后应该运行的函数。我们通常像这样使用实际的“回调”一词:

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 函数将某个其他函数(即回调)作为其参数,并在您执行查询后执行该函数。如果你想在不使用“回调”这个词的情况下做同样的事情,你可以使用像 fsociety 这样的 await/async 函数,或者你明确地写出你的代码,而不是创建以其他函数作为参数的函数。

这与上面的代码功能相同:

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

回调地狱是不可避免的,但是一旦你掌握了它,它真的不会太糟糕。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-12
    • 2021-01-09
    • 1970-01-01
    • 2019-09-30
    • 2018-01-03
    • 2018-04-09
    • 1970-01-01
    • 2019-02-27
    相关资源
    最近更新 更多