【问题标题】:NODEJS, PUG, EXPRESS - Cannot read property 'length' of undefinedNODEJS、PUG、EXPRESS - 无法读取未定义的属性“长度”
【发布时间】:2018-08-09 21:46:23
【问题描述】:

我有一个 API,我对其进行了调整,可以对我的数据库进行 2 次调用并下拉信息。我可以在控制台日志中看到结果,所以我知道它正在工作

下一部分是渲染视图时,我需要在两个地方显示结果

这是对数据库进行 2 次调用的 API 代码

function apples(req, res, next) {
  sql.connect(config, function () {
    var request = new sql.Request();
    request.query("select price from table WHERE fruit = 'apples'", function(err, recordsetapples) {
      var arrayLength = recordsetapples.length;
      for (var i = 0; i < arrayLength; i++) {
        console.log(recordsetapples[i]["price"]);
      };
      res.render('index', { resultsapples: recordsetapples });
        return next();
    });
  });
};

function pear(req, res, next) {
  sql.connect(config, function () {
    var request = new sql.Request();
    request.query("select price from table WHERE fruit = 'pear'", function(err, recordsetpear) {
      var arrayLength = recordsetpear.length;
      for (var i = 0; i < arrayLength; i++) {
        console.log(recordsetpear[i]["price"]);
      };
      res.render('index', { resultspear: recordsetpear });
        next();
    });
  });
};



app.get('/fruit', apples, pear);

所以在运行之后我可以在控制台日志中看到价格打印.. 然后我看到这个错误

Cannot read property 'length' of undefined

如果价格出现,我希望看到什么...要获取该信息,我有此代码

      tr
        th.hidden-phone Fruit
        th.hidden-phone Price
      tr
      each val in resultsapples
        td.hidden-phone Apples
        td.hidden-phone !{val.price}
      tr
      each val in resultspear
        td.hidden-phone Pears
        td.hidden-phone !{val.price}

【问题讨论】:

  • 虽然与您的问题没有明确相关,但您不会在 sql 代码中检查错误对象。您应该更新它以确保没有错误并使用回调等来确定是否有错误

标签: node.js function api for-loop pug


【解决方案1】:

问题是您的视图同时需要两个列表,但您尝试使用每个列表分别呈现视图两次,这意味着在任一情况下,视图中的一个列表将是undefined

即使您要解决此问题,这种方法也不会起作用,因为在第一个res.render 之后,HTTP 响应将结束并返回到客户端。理想情况下,您希望为两个结果集都访问一次数据库,然后渲染视图,例如

sql.connect(config, () => {
  const request = new sql.Request();
  request.query("select price from table WHERE fruit = 'apples' OR fruit = 'pear'", (err, result) => {
    res.render('index', { 
      resultsapples: result.recordsets[0], 
      resultspear: result.recordsets[1]
    });
  });
});

【讨论】:

  • 所以这已经消除了错误,它现在显示索引页面,但索引页面仍然没有显示价格部分
  • @zoomer 看起来我的代码中有错字,resultapples 应该是 resultsapples & resultpears 应该是 resultspears
【解决方案2】:

正如 James 所说,您的回调是异步的,因此您尝试渲染视图两次。您还需要在 sql 函数中进行一些错误处理

function apples(cb) {
  sql.connect(config, function () {
    var request = new sql.Request();
    request.query("select price from table WHERE fruit = 'apples'", function(err, recordsetapples) {
      if(err) {
          return cb(err);
      }
      var arrayLength = recordsetapples.length;
      for (var i = 0; i < arrayLength; i++) {
        console.log(recordsetapples[i]["price"]);
      };
      cb(false, recordsetapples);
    });
  });
};

function pear(cb) {
  sql.connect(config, function () {
    var request = new sql.Request();
    request.query("select price from table WHERE fruit = 'pear'", function(err, recordsetpear) {

      if(err){
          return cb(err)
      }
      var arrayLength = recordsetpear.length;
      for (var i = 0; i < arrayLength; i++) {
        console.log(recordsetpear[i]["price"]);
      };
      cb(false,recordsetpear);
    });
  });
};



app.get('/fruit', (req,res) => {
     apples((appleerr,appleset) => {
         if(appleerr){
          //render error page
         } else {
           pear((pearerr, pearset) => {
              if(pearerr) {
                  //render error page
              } else {
                return res.render('index', { 
                   resultapples: appleset, 
                   resultpears: pearset
                });
              }
           })
         }
     });
});

现在记录一下,我不喜欢像这样嵌套回调,所以我实际上建议你查看 Promises 和/或async/await,但我不确定你的编码水平,所以我没有想一次性向你抛出太多概念。

此外,虽然 James 已将您的 SQL 语句合并为一个(这可能是您的正确方法),但我将它们分开,不知道您是否在其他地方重用这些单独的代码片段,因此不想将它们组合起来。

如果您对 Promise 实现感兴趣,它可能如下所示:

function apples() {
    return new Promise((resolve,reject) => {
      sql.connect(config, function () {
        var request = new sql.Request();
        request.query("select price from table WHERE fruit = 'apples'", function(err, recordsetapples) {
          if(err) {
              reject(err);
          }
          var arrayLength = recordsetapples.length;
          for (var i = 0; i < arrayLength; i++) {
            console.log(recordsetapples[i]["price"]);
          };
          resolve(recordsetapples);
        });
      });
    };

    function pear() {
        return new Promise((resolve,reject) => {

      sql.connect(config, function () {
        var request = new sql.Request();
        request.query("select price from table WHERE fruit = 'pear'", function(err, recordsetpear) {

          if(err){
              reject(err)
          }
          var arrayLength = recordsetpear.length;
          for (var i = 0; i < arrayLength; i++) {
            console.log(recordsetpear[i]["price"]);
          };
          resolve(recordsetpear);
        });
      });
       });
    };



    app.get('/fruit', (req,res) => {
         var applePromise = apples()
         var pearsPromise = applePromise.then((appleSet)) {
             return pear()
         }

         Promise.all([applePromise,pearsPromise]).then((([appleSet,pearSet]) => {
             res.render('index', { 
                resultapples: appleSet, 
                resultpear: pearSet
            });
         }).catch((err) => {
             //render error
         })
    });

【讨论】:

  • 即使两个请求都需要分开,我仍然主张至少使用单个数据库连接。此外,我希望摆脱的代码中有很多重复。
  • 是的,这是一个有效点,或者取决于使用池的库
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-07
  • 1970-01-01
  • 2020-11-01
  • 1970-01-01
  • 2020-06-02
  • 1970-01-01
相关资源
最近更新 更多