首页 > 解决方案 > 来自异步函数的 Node.js Express 结果集不可用作函数值

问题描述

在 Node Express 应用程序中,替代产品通过产品 ID 连接到产品。替代产品(在单独的表中)与 ProductAlternatives.AlternativeProductId=Products.Id 上的产品正确连接。我正在尝试生成一个嵌套的 JSON 结构,其中替代产品(如果可用)显示在一个单独的数组中。

我得到的结果是一个扁平的 JSON 结构,如下所示:

[
  {
    "Id": 1,
    "ProductName": "2 Zits My Style",
    "Description": "2 zits | stof | Stof grof geweven lichtgrijs",
    "Price": "579.00",
    "Picture": "~/UserImages/8195299-254-02.jpg",
    "CatID": 5,
    "alternateproducts": {}
  },
  {
    "Id": 4,
    "ProductName": "Slaapbank Hervik",
    "Description": "Cubos 50 lever",
    "Price": "1.499.00",
    "Picture": "~/UserImages/8202978-06.jpg",
    "CatID": 11,
    "alternateproducts": {}
  },

所以,没有替代产品。第一个产品的属性 alternateproducts 应该正好包含 2 个替代产品,如下所示:

[
  {
    "Id": 1,
    "ProductName": "2 Zits My Style",
    "Description": "2 zits | stof | Stof grof geweven lichtgrijs",
    "Price": "579.00",
    "Picture": "~/UserImages/8195299-254-02.jpg",
    "CatID": 5,
    "alternateproducts": {
                           [ 
                             {
                               "Id": 24,
                               "ProductName": "Zitbank Ravenia",
                               "Description": "2 zits | stof | Stof ribstof taupe",
                               "Price": "1.139.00",
                               "Picture": "~/UserImages/8192530-94-02.jpg",
                               "CatID": 5
                             },
                             {
                               "Id": 25,
                               "ProductName": " Zitbank Gino",
                               "Description": "2 zits | Stof velours okergeel",
                               "Price": "499.00",
                               "Picture": "~/UserImages/8194150-01.jpg",
                               "CatID": 5
                             } 
                           ]
                         }
  },
  {
    "Id": 4,
    "ProductName": "Slaapbank Hervik",
    "Description": "Cubos 50 lever",
    "Price": "1.499.00",
    "Picture": "~/UserImages/8202978-06.jpg",
    "CatID": 11
  }

代码如下:

       var structured;

       // Application
        app.route('/products')
        // GET endpoint
        .get(cors(), function(req, res) {
    
            // create Request object
            var request = new appmodule.sql.Request();
                
            // query to the database and get all the records
            request.query('SELECT * FROM Products', function (err, recordset) {
                
                if (err) console.log(err)
    
                GenerateStructuredJSON(recordset);
                res.json(structured);
            });

        });

        function GenerateStructuredJSON(recordset) {
            var products = recordset.recordset;
            structured = getNestedProducts(products);

            function getNestedProducts(prod) {
                for(var i = 0; i < prod.length; ++i) {
                    var productId = prod[i].Id;         
                    var alternativeproducts = getAlternativeProducts(productId);
                    console.log(alternativeproducts); // logging nothing but Promise { <pending> }
                    if(alternativeproducts) {
                        prod[i].alternateproducts = alternativeproducts;
                    }
                }
                return prod;
            }
        }

        async function getAlternativeProducts(prodID) {
            const rs = await new Promise(function(resolve, reject,) {
                var request = new appmodule.sql.Request();
                request.input('prodid', sql.Int , prodID);
                request.query('SELECT Products.* FROM Products ' +
                'RIGHT JOIN ProductAlternatives ON ProductAlternatives.AlternativeProductId=Products.Id ' +
                'WHERE ProductAlternatives.ProductId=@prodid', function(err, res) {
                    if (err) throw err
                    resolve(res.recordset);
                })
            });
            console.log(rs); // logging json product structures correctly
            return rs;
        }

奇怪的是,来自异步函数的结果集 rs 使用 console.log(rs); 正确记录,但是一旦它连接到函数 getNestedProducts 中的 var Alternativeproducts,它只记录空Promise { <pending> }的。所以结果集当时似乎丢失或不可用。

标签: sqlnode.jsexpress

解决方案


原因是 node.js 中的 async 函数只是一个 Promise。线

 var alternativeproducts = getAlternativeProducts(productId);

将 Promise 分配给替代产品。

您可以使函数 GenerateStructuredJSON(recordset) 异步,然后在您的主函数中,您可以

 await GenerateStructuredJSON(recordset)

但是随后您将需要等待为每个产品创建的 getAlternativeProducts 的所有 Promises。

我认为更好的方法是使用 LEFT OUT jOIN 让一个 sql 包含替代产品作为结果的一部分。然后,您只需将生成的 JSON 结构化为预期的格式。

还有,之后

if (err) console.log(err)

它不应该继续,即:

    if (err) {
        console.log(err);
        return res.json(err);
    }

推荐阅读