简体   繁体   English

如何在NodeJs中发送回响应之前等待循环完成?

[英]How to wait for a loop to finish running before sending back a response in NodeJs?

I'm trying to send back an array of objects after a GET request to a URL but I can't figure out how to structure the logic so the return array fully populates before sending it to the client. 我试图在对URL的GET请求之后将对象数组发送回去,但是我不知道如何构造逻辑,因此返回数组在发送给客户端之前会完全填充。

Below is my server side code for responding to the request. 下面是我的服务器端代码,用于响应请求。 I used passport.js previously in the code to create a login portal and user object. 我之前在代码中使用过passport.js来创建登录门户和用户对象。 I'm trying to take the "connections" array from the user who is making the request and sending them back an array of objects with the connection's name and picture. 我正在尝试从发出请求的用户那里获取“连接”数组,并将其发送回带有连接名称和图片的对象数组。 I know that the code below is incorrect syntax wise but it's an overview of what I'm trying to accomplish. 我知道以下代码在语法上是不正确的,但这是我要完成的工作的概述。 I've tried doing it the callback way but that just kept leading me in circles because I couldn't figure out the correct logic for it. 我尝试过以回调的方式进行操作,但这一直使我陷入困境,因为我无法找出正确的逻辑。

router.get('/data', function(req, res, next) {
    var IdArr = req.user.connections;

    var retArr = [];

    function getUsers() {
        for (i = 0; i < IdArr.length; i++) {
            User.getUserById(IdArr[i], function(err, patient) {
                retArr[i] = {name:patient.name, pic:patient.profileImage};
            });
        }
    }

    function getDataAndSend() {
        function(getUsers(), function sendRes() { // I know this is incorrect syntax
            console.log(retArr);
            res.json(retArr);
        });
    }

    getDataAndSend();
});

First of all, you should declare i , and when you do it should be with block-scope ( let ), so that the nested callback function will use the same variable. 首先,您应该声明i ,并且在进行声明时应使用block-scope( let ),以便嵌套的回调函数将使用相同的变量。

You could check how many entries in retArr have been retrieved and call res.json once you know you have them all. 您可以检查retArr中已经检索了多少条目,并在知道所有内容后调用res.json

router.get('/data', function(req, res, next) {
    var IdArr = req.user.connections;
    var retArr = [];
    for (let i = 0; i < IdArr.length; i++) {
        User.getUserById(IdArr[i], function(err, patient) {
            retArr[i] = {name:patient.name, pic:patient.profileImage};
            if (Object.keys(retArr).length === IdArr.length) res.json(retArr);
        });
    }
});

I think the easiest way to deal with these things is with Promises. 我认为处理这些问题的最简单方法是使用Promises。 Any async function written in the callback way (eg this User.getUserById) can be turned into a function that returns a promise. 任何以回调方式编写的异步函数(例如,此User.getUserById)都可以转换为返回承诺的函数。 You just wrap the call around a new Promise and resolve when you're done. 您只需将呼叫包装在一个新的Promise中,并在完成后解决。

Say in your case. 说你的情况。

function promiseGetById(id) {
    return new Promise((resolve, reject) =>
        User.getUserById(id, (err, pat) => resolve(pat))
    );
}

Then something like 然后像

Promise.all(IdArr.map(id => promiseGetById(id))).then(arr =>
    res.json(
        arr.map(patient => ({ name: patient.name, pic: patient.profileImage }))
    )
);

Alternatively if you don't like promises you can do it by having a counter or something which in each callback you increment and then in your callback you res.json when the counter is the correct value. 或者,如果您不喜欢诺言,则可以通过拥有一个计数器或在每个回调中递增的东西来实现它,然后在计数器为正确值时在回调中添加res.json。

Change all your function logic to return promises and use async/await for code clarity. 更改所有函数逻辑以返回承诺,并使用async/await来使代码清晰。

const getUserById = (id) => {
  return new Promise((resolve, reject) => {
    User.getUserById(IdArr[i], function(err, patient) {
      resolve({name:patient.name, pic:patient.profileImage});
    });
  });
}

const getAllUsers = async(idArr) => {
  const retArr = [];

  // for...of loop to await without continuing the loop
  // but this will execute only sequentially
  for (let id of idArr) {
    const ret = await getUserById(id);
    retArr.push(ret);
  }

  // for parallel execution, use Promise.all()
  await Promise.all([...idArr.map(id => getUserById(id))]);

  return retArr;
}

router.get('/data', async (req, res, next) => {
  var IdArr = req.user.connections;
  var retArr = await getAllUsers(IdArr);

  console.log(retArr);
  res.json(retArr);
});

You seem to be trying to extract way to much functions for an algorithm that isn't that complicated. 您似乎正在尝试为不那么复杂的算法提取许多函数的方法。 The code below initialy extract the information it needs for the request. 以下代码初步提取了请求所需的信息。 Then, it populates the array needed for the response and simply sends it. 然后,它填充响应所需的数组并简单地发送它。

router.get('/data', (req, res, next) => {
    const idArray = req.user.connections;

    let responseArray = [];

    // loop to populate responseArray
    for (let id of idArray) {
        User.getUserById(id, (err, patient) => {
            // add to the end of the array the patient informations
            responseArray.push({
                name: patient.name,
                pic: patient.profileImage
            });
        });
    }

    // send back responseArray
    res.json(responseArray);
});

暂无
暂无

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

相关问题 等待httpRequests完成后再发送响应-ParseServer - Wait for httpRequests to finish before sending response - ParseServer 等待查询完成后再发送响应 - wait for query to finish before sending response 如何异步执行多个猫鼬查询并等到所有查询都执行完再发送响应? - How to execute multiple mongoose queries asynchronously and wait until all of them finish executing before sending response? 等待 mysql 在 for 循环中完成查询,然后在 nodeJS 中完成 function - Wait for mysql to finish queries in a for loop before finishing a function in nodeJS NodeJS:如何在继续执行代码之前等待异步请求的 for 循环完成? - NodeJS: How to wait for a for-loop of async requests to finish before proceeding with code? 在将响应发送回客户之前,您如何等待Mandrill的交付响应? - How do you wait for a delivery response from Mandrill before sending response back to client? NodeJS Plotly - 如何在继续之前等待 getImage 完成 - NodeJS Plotly - how to wait for getImage to finish before continuing 如何在返回响应之前等待数据库完成查询? - How to wait for database to finish querying before returning a response? 如何等待 function 完成后再运行另一个或 rest 的代码? - How to wait for function to finish before running another one or rest of the code? 如何在继续执行脚本之前有效地等待链接文件完成运行 - How to efficiently wait for a linked file to finish running before continuing with script
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM