简体   繁体   English

Express.js GET请求在第一次调用时未返回数据

[英]Express.js GET request not returning data on first call

I'm building an application using Node/Express/MongoDB (first time with all these) that will let me pull data from the DB and display it on an Express page. 我正在使用Node / Express / MongoDB(这是所有这些第一次)构建一个应用程序,它将允许我从数据库中提取数据并将其显示在Express页面上。 This is what the GET request looks like: 这是GET请求的样子:

var str = "";

app.route('/view-reports').get(function(req, res) {
  var cursor = collections.find({});

  cursor.each(function(err, item) {
    if (item != null) {
      console.log(str);
      str = str + "Substance: " + item.substance + "<br>";
    }
    if (err) {
      console.log(err);
    }
  });
  console.log(str);
  res.send(str);
  str = "";
});

I would expect this to return something like this: 我希望这会返回如下内容:

Substance: a 物质:

Substance: b 物质:b

Substance: c 物质:c

However, the initial request does not return anything at all. 但是,初始请求根本不返回任何内容。 The second request will return the above. 第二个请求将返回以上内容。 If I enclose res.send(str) in an if conditional it simply will not load until a second request is made. 如果我将res.send(str)在if条件中,则在提出第二个请求之前,它根本不会加载。

cursor.each() is asynchronous. cursor.each()是异步的。 That means it runs sometimes LATER, after your res.send(str) , thus you get the previous version of str . 这意味着它有时会在res.send(str)之后运行,因此您可以获得str的先前版本。 You need to collect all the data first and then send your response only when you have all the data. 您需要先收集所有数据,然后仅在拥有所有数据时才发送响应。

If you want all the data, then you could use promises and .toArray() like this: 如果需要所有数据,则可以使用promise和.toArray()如下所示:

app.route('/view-reports').get(function(req, res) {
  collections.find({}).toArray().then(data => {
      let result = data.map(item => {
          return "Substance: " + item.substance + "<br>";
      }).join("");
      res.send(result);
  }).catch(err => {
      // database error
      console.log(err);
      res.sendStatus(500);
  });
});

Note: This also wisely gets rid of the str variable which was outside the scope of the request and thus could easily lead to a concurrency bug when multiple requests were in flight at the same time (from different users). 注意:这也明智地摆脱了超出请求范围的str变量,因此当同时有多个请求(来自不同用户)运行时,很容易导致并发错误。

Create a router specifically for substances and use it in app. 创建专门用于物质的路由器,并在应用程序中使用它。 Instead of breaks, you can create a ul, also, that processing should happen on the front end. 除了中断之外,您还可以创建一个ul,该处理也应该在前端进行。 Separate your concerns. 分开关注。 The server shouldn't have to worry about any rendering and etc. One purpose per process. 服务器不必担心任何渲染等。每个进程一个目的。

The routers can be created per resource. 可以按资源创建路由器。 Create a router for substances, for cats, for dogs. 为物质,猫,狗创建路由器。 Each individual router has it's own get post delete and puts that allow you to modify that resource. 每个路由器都有其自己的获取后删除和放置操作,使您可以修改该资源。 app can use all the routers at once. app可以一次使用所有路由器。

app.use(catRouter); app.use(mooseRouter); app.use(platypusRouter);

 const { Router } = require('express'); const createError = require('http-errors'); let substanceRouter = new Router(); function buildElement(arr) { let start = ''; arr.forEach(val => { if(!val) return; start += `Substance : ${val}<br>`; }); return start; } subtanceRouter.get('/endpoint/whatever', function(req, res, next) { collectios.find({}) .then(results => { if(!results) throw new Error('Resource Not Found'); let output = buildElement(results); res.json(output); next(); }) .catch(err => next(createError(404, err.message))); }) app.use(substanceRouter); 

Alternately we can write : 或者我们可以写:

 let output = results .filter(sub => !!sub) .join('<br>'); res.json(output); 

But be advised this will add memory overhead, generates a completely new array to house the results, consuming at worst, O(n) memory. 但是建议这样做会增加内存开销,生成一个全新的数组来存储结果,最坏的情况是消耗O(n)内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM