首页 > 解决方案 > Node.js - 如何使用 MySQL 查询从 for 循环中返回带有数组的回调?

问题描述

我正在尝试在我的 Node.js 应用程序上获取虚拟社区列表,然后使用回调函数返回它。当我用回调调用 getList() 方法时,它返回一个空数组。

const mysqli = require("../mysqli/connect");

class Communities{

  getList(callback){
    var list = [];

    mysqli.query("SELECT * FROM communities", (err, communities) => {

      for(let i = 0; i < communities.length; i++){
        mysqli.query("SELECT name FROM users WHERE id='"+ communities[i].host +"'", (err, host) => {

          list.push({
            "id": communities[i].id,
            "name": communities[i].name,
            "hostID": communities[i].host,
            "hostName": host[0].name,
            "verified": communities[i].verified,
            "people": communities[i].people
          });

        });
      }

      callback(list);
    });
  }

}

new Communities().getList((list) => {
  console.log(list);
});

我需要将 for 循环设为异步并在 for 循环结束时调用回调。请让我知道如何做到这一点。谢谢。

标签: javascriptnode.jsfor-loopasynchronouscallback

解决方案


如果你必须组合多个回调,回调会变得非常丑陋,这就是为什么发明了 Promises 来简化它。要在您的情况下使用 Promise,您必须在查询数据库时首先创建一个 Promise ¹:

 const query = q => new Promise((resolve, reject) => mysqli.query(q, (err, result) => err ? reject(err) : resolve(result)));

现在执行多个查询将返回多个 Promise,可以将它们组合Promise.all为一个 Promise²:

 async getList(){
   const communities = await query("SELECT * FROM communities");

   const result = await/*³*/ Promise.all(communities.map(async community => {
      const host = await query(`SELECT name FROM users WHERE id='${community.host}'`);/*⁴*/

       return {
        ...community,
        hostName: host[0].name,
       };
    }));

    return result;
  }

现在您可以通过以下方式轻松获得结果:

 new Communities().getList().then(list => {
   console.log(list);
 });

继续阅读:

使用 Promise - Google Developers

理解 async / await - Ponyfoo

笔记:

¹:如果您更频繁地这样做,您可能更应该使用原生支持 Promise 的 mysql 库,这样可以节省大量工作。

²:通过请求是并行完成的,这意味着它比一个接一个地完成要快得多(可以使用 for 循环并在其中等待)。

³:那await是多余的,但我更喜欢保留它以将其标记为异步操作。

⁴:我想这也可以使用一个 SQL 查询来完成,所以如果它对你的用例来说太慢(我怀疑)你应该优化查询本身。


推荐阅读